ForegroundUtils.java revision 34322b73c1e09907cb007e86bae77c744b338cd7
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 static final boolean DBG = false; 30 private final String TAG = "ForegroundUtils"; 31 private final IActivityManager mIActivityManager; 32 33 private final Object mLock = new Object(); 34 private final SparseArray<Boolean> mForegroundUids = new SparseArray<Boolean>(1); 35 private final SparseArray<List<Callback>> mBackgroundCallbacks = 36 new SparseArray<List<Callback>>(); 37 38 private static class Singleton { 39 private static final ForegroundUtils INSTANCE = new ForegroundUtils(); 40 } 41 42 private ForegroundUtils() { 43 mIActivityManager = ActivityManagerNative.getDefault(); 44 try { 45 mIActivityManager.registerProcessObserver(this); 46 } catch (RemoteException e) { 47 // Should not happen! 48 Log.e(TAG, "ForegroundUtils: could not get IActivityManager"); 49 } 50 } 51 52 public interface Callback { 53 void onUidToBackground(int uid); 54 } 55 56 public static ForegroundUtils getInstance() { 57 return Singleton.INSTANCE; 58 } 59 60 /** 61 * Checks whether the specified UID has any activities running in the foreground, 62 * and if it does, registers a callback for when that UID no longer has any foreground 63 * activities. This is done atomically, so callers can be ensured that they will 64 * get a callback if this method returns true. 65 * 66 * @param callback Callback to be called 67 * @param uid The UID to be checked 68 * @return true when the UID has an Activity in the foreground and the callback 69 * , false otherwise 70 */ 71 public boolean registerUidToBackgroundCallback(Callback callback, int uid) { 72 synchronized (mLock) { 73 if (!isInForegroundLocked(uid)) { 74 return false; 75 } 76 // This uid is in the foreground; register callback for when it moves 77 // into the background. 78 List<Callback> callbacks = mBackgroundCallbacks.get(uid); 79 if (callbacks == null) { 80 callbacks = new ArrayList<Callback>(); 81 mBackgroundCallbacks.put(uid, callbacks); 82 } 83 callbacks.add(callback); 84 return true; 85 } 86 } 87 88 /** 89 * @param uid The UID to be checked 90 * @return whether the UID has any activities running in the foreground 91 */ 92 public boolean isInForeground(int uid) { 93 synchronized (mLock) { 94 return isInForegroundLocked(uid); 95 } 96 } 97 98 /** 99 * @return the UID of the package currently in the foreground, or -1 100 * if it can't be determined. 101 */ 102 public int getForegroundUid() { 103 synchronized (mLock) { 104 for (int i = 0; i < mForegroundUids.size(); i++) { 105 if (mForegroundUids.valueAt(i).booleanValue()) { 106 return mForegroundUids.keyAt(i); 107 } 108 } 109 } 110 return -1; 111 } 112 113 private boolean isInForegroundLocked(int uid) { 114 Boolean inForeground = mForegroundUids.get(uid); 115 return inForeground != null ? inForeground.booleanValue() : false; 116 } 117 118 private void handleUidToBackground(int uid) { 119 ArrayList<Callback> pendingCallbacks = null; 120 synchronized (mLock) { 121 List<Callback> callbacks = mBackgroundCallbacks.get(uid); 122 if (callbacks != null) { 123 pendingCallbacks = new ArrayList<Callback>(callbacks); 124 // Only call them once 125 mBackgroundCallbacks.remove(uid); 126 } 127 } 128 // Release lock for callbacks 129 if (pendingCallbacks != null) { 130 for (Callback callback : pendingCallbacks) { 131 callback.onUidToBackground(uid); 132 } 133 } 134 } 135 136 @Override 137 public void onForegroundActivitiesChanged(int pid, int uid, 138 boolean foregroundActivities) throws RemoteException { 139 synchronized (mLock) { 140 mForegroundUids.put(uid, foregroundActivities); 141 } 142 if (DBG) Log.d(TAG, "Foreground changed, PID: " + Integer.toString(pid) + " UID: " + 143 Integer.toString(uid) + " foreground: " + foregroundActivities); 144 if (!foregroundActivities) { 145 handleUidToBackground(uid); 146 } 147 } 148 149 150 @Override 151 public void onProcessDied(int pid, int uid) throws RemoteException { 152 synchronized (mLock) { 153 mForegroundUids.remove(uid); 154 } 155 handleUidToBackground(uid); 156 } 157 158 @Override 159 public void onProcessStateChanged(int pid, int uid, int procState) 160 throws RemoteException { 161 // Don't care 162 } 163} 164