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