ForegroundUtils.java revision da772582c17e3f5ffe36e4cab3e1ede3cba32060
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.nfc; 17 18import java.util.ArrayList; 19import java.util.List; 20 21import android.app.ActivityManagerNative; 22import android.app.IActivityManager; 23import android.app.IProcessObserver; 24import android.os.RemoteException; 25import android.util.Log; 26import android.util.SparseArray; 27 28public class ForegroundUtils extends IProcessObserver.Stub { 29 private final String TAG = "ForegroundUtils"; 30 private final IActivityManager mIActivityManager; 31 32 private final Object mLock = new Object(); 33 private final SparseArray<Boolean> mForegroundUids = new SparseArray<Boolean>(1); 34 private final SparseArray<List<Callback>> mBackgroundCallbacks = 35 new SparseArray<List<Callback>>(); 36 37 private static class Singleton { 38 private static final ForegroundUtils INSTANCE = new ForegroundUtils(); 39 } 40 41 private ForegroundUtils() { 42 mIActivityManager = ActivityManagerNative.getDefault(); 43 try { 44 mIActivityManager.registerProcessObserver(this); 45 } catch (RemoteException e) { 46 // Should not happen! 47 Log.e(TAG, "ForegroundUtils: could not get IActivityManager"); 48 } 49 } 50 51 public interface Callback { 52 void onUidToBackground(int uid); 53 } 54 55 public static ForegroundUtils getInstance() { 56 return Singleton.INSTANCE; 57 } 58 59 /** 60 * Checks whether the specified UID has any activities running in the foreground, 61 * and if it does, registers a callback for when that UID no longer has any foreground 62 * activities. This is done atomically, so callers can be ensured that they will 63 * get a callback if this method returns true. 64 * 65 * @param callback Callback to be called 66 * @param uid The UID to be checked 67 * @return true when the UID has an Activity in the foreground and the callback 68 * , false otherwise 69 */ 70 public boolean registerUidToBackgroundCallback(Callback callback, int uid) { 71 synchronized (mLock) { 72 if (!isInForegroundLocked(uid)) { 73 return false; 74 } 75 // This uid is in the foreground; register callback for when it moves 76 // into the background. 77 List<Callback> callbacks = mBackgroundCallbacks.get(uid); 78 if (callbacks == null) { 79 callbacks = new ArrayList<Callback>(); 80 mBackgroundCallbacks.put(uid, callbacks); 81 } 82 callbacks.add(callback); 83 return true; 84 } 85 } 86 87 /** 88 * @param uid The UID to be checked 89 * @return whether the UID has any activities running in the foreground 90 */ 91 public boolean isInForeground(int uid) { 92 synchronized (mLock) { 93 return isInForegroundLocked(uid); 94 } 95 } 96 97 boolean isInForegroundLocked(int uid) { 98 Boolean inForeground = mForegroundUids.get(uid); 99 return inForeground != null ? inForeground.booleanValue() : false; 100 } 101 102 void handleUidToBackground(int uid) { 103 ArrayList<Callback> pendingCallbacks = null; 104 synchronized (mLock) { 105 List<Callback> callbacks = mBackgroundCallbacks.get(uid); 106 if (callbacks != null) { 107 pendingCallbacks = new ArrayList<Callback>(callbacks); 108 // Only call them once 109 mBackgroundCallbacks.remove(uid); 110 } 111 } 112 // Release lock for callbacks 113 if (pendingCallbacks != null) { 114 for (Callback callback : pendingCallbacks) { 115 callback.onUidToBackground(uid); 116 } 117 } 118 } 119 120 @Override 121 public void onForegroundActivitiesChanged(int pid, int uid, 122 boolean foregroundActivities) throws RemoteException { 123 synchronized (mLock) { 124 mForegroundUids.put(uid, foregroundActivities); 125 } 126 if (!foregroundActivities) { 127 handleUidToBackground(uid); 128 } 129 } 130 131 132 @Override 133 public void onProcessDied(int pid, int uid) throws RemoteException { 134 synchronized (mLock) { 135 mForegroundUids.remove(uid); 136 } 137 handleUidToBackground(uid); 138 } 139 140 @Override 141 public void onProcessStateChanged(int pid, int uid, int procState) 142 throws RemoteException { 143 // Don't care 144 } 145} 146