diff options
21 files changed, 443 insertions, 187 deletions
@@ -67,10 +67,11 @@ LOCAL_SRC_FILES += \ core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \ core/java/android/accessibilityservice/IEventListener.aidl \ core/java/android/accounts/IAccountsService.aidl \ + core/java/android/app/IActivityController.aidl \ core/java/android/app/IActivityPendingResult.aidl \ core/java/android/app/IActivityWatcher.aidl \ core/java/android/app/IAlarmManager.aidl \ - core/java/android/app/IBackupAgent.aidl \ + core/java/android/app/IBackupAgent.aidl \ core/java/android/app/IInstrumentationWatcher.aidl \ core/java/android/app/INotificationManager.aidl \ core/java/android/app/ISearchManager.aidl \ @@ -88,12 +89,12 @@ LOCAL_SRC_FILES += \ core/java/android/bluetooth/IBluetoothDevice.aidl \ core/java/android/bluetooth/IBluetoothDeviceCallback.aidl \ core/java/android/bluetooth/IBluetoothHeadset.aidl \ - core/java/android/content/IContentService.aidl \ + core/java/android/content/IContentService.aidl \ core/java/android/content/IIntentReceiver.aidl \ core/java/android/content/IIntentSender.aidl \ core/java/android/content/ISyncAdapter.aidl \ core/java/android/content/ISyncContext.aidl \ - core/java/android/content/ISyncStatusObserver.aidl \ + core/java/android/content/ISyncStatusObserver.aidl \ core/java/android/content/pm/IPackageDataObserver.aidl \ core/java/android/content/pm/IPackageDeleteObserver.aidl \ core/java/android/content/pm/IPackageInstallObserver.aidl \ diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 6c2560d..4ac3b9e 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -612,6 +612,7 @@ public class Activity extends ContextThemeWrapper // set by the thread after the constructor and before onCreate(Bundle savedInstanceState) is called. private Instrumentation mInstrumentation; private IBinder mToken; + private int mIdent; /*package*/ String mEmbeddedID; private Application mApplication; /*package*/ Intent mIntent; @@ -789,9 +790,6 @@ public class Activity extends ContextThemeWrapper protected void onCreate(Bundle savedInstanceState) { mVisibleFromClient = mWindow.getWindowStyle().getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay, true); - // uses super.getSystemService() since this.getSystemService() looks at the - // mSearchManager field. - mSearchManager = (SearchManager) super.getSystemService(Context.SEARCH_SERVICE); mCalled = true; } @@ -2531,6 +2529,7 @@ public class Activity extends ContextThemeWrapper */ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData, boolean globalSearch) { + ensureSearchManager(); mSearchManager.startSearch(initialQuery, selectInitialQuery, getComponentName(), appSearchData, globalSearch); } @@ -3241,6 +3240,24 @@ public class Activity extends ContextThemeWrapper return getSharedPreferences(getLocalClassName(), mode); } + private void ensureSearchManager() { + if (mSearchManager != null) { + return; + } + + // uses super.getSystemService() since this.getSystemService() looks at the + // mSearchManager field. + mSearchManager = (SearchManager) super.getSystemService(Context.SEARCH_SERVICE); + int ident = mIdent; + if (ident == 0) { + if (mParent != null) ident = mParent.mIdent; + if (ident == 0) { + throw new IllegalArgumentException("no ident"); + } + } + mSearchManager.setIdent(ident); + } + @Override public Object getSystemService(String name) { if (getBaseContext() == null) { @@ -3251,6 +3268,7 @@ public class Activity extends ContextThemeWrapper if (WINDOW_SERVICE.equals(name)) { return mWindowManager; } else if (SEARCH_SERVICE.equals(name)) { + ensureSearchManager(); return mSearchManager; } return super.getSystemService(name); @@ -3450,14 +3468,17 @@ public class Activity extends ContextThemeWrapper Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance, Configuration config) { - attach(context, aThread, instr, token, application, intent, info, title, parent, id, + attach(context, aThread, instr, token, 0, application, intent, info, title, parent, id, lastNonConfigurationInstance, null, config); } - final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, - Application application, Intent intent, ActivityInfo info, CharSequence title, - Activity parent, String id, Object lastNonConfigurationInstance, - HashMap<String,Object> lastNonConfigurationChildInstances, Configuration config) { + final void attach(Context context, ActivityThread aThread, + Instrumentation instr, IBinder token, int ident, + Application application, Intent intent, ActivityInfo info, + CharSequence title, Activity parent, String id, + Object lastNonConfigurationInstance, + HashMap<String,Object> lastNonConfigurationChildInstances, + Configuration config) { attachBaseContext(context); mWindow = PolicyManager.makeNewWindow(this); @@ -3470,6 +3491,7 @@ public class Activity extends ContextThemeWrapper mMainThread = aThread; mInstrumentation = instr; mToken = token; + mIdent = ident; mApplication = application; mIntent = intent; mComponent = intent.getComponent(); @@ -3554,9 +3576,6 @@ public class Activity extends ContextThemeWrapper final void performPause() { onPause(); - - // dismiss the search dialog if it is open - mSearchManager.stopSearch(); } final void performUserLeaving() { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index dfa8139..ec7714d 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -881,11 +881,11 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } - case SET_ACTIVITY_WATCHER_TRANSACTION: { + case SET_ACTIVITY_CONTROLLER_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - IActivityWatcher watcher = IActivityWatcher.Stub.asInterface( + IActivityController watcher = IActivityController.Stub.asInterface( data.readStrongBinder()); - setActivityWatcher(watcher); + setActivityController(watcher); return true; } @@ -1052,6 +1052,22 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + + case REGISTER_ACTIVITY_WATCHER_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IActivityWatcher watcher = IActivityWatcher.Stub.asInterface( + data.readStrongBinder()); + registerActivityWatcher(watcher); + return true; + } + + case UNREGISTER_ACTIVITY_WATCHER_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IActivityWatcher watcher = IActivityWatcher.Stub.asInterface( + data.readStrongBinder()); + unregisterActivityWatcher(watcher); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -2105,13 +2121,13 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - public void setActivityWatcher(IActivityWatcher watcher) throws RemoteException + public void setActivityController(IActivityController watcher) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(watcher != null ? watcher.asBinder() : null); - mRemote.transact(SET_ACTIVITY_WATCHER_TRANSACTION, data, reply, 0); + mRemote.transact(SET_ACTIVITY_CONTROLLER_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); reply.recycle(); @@ -2290,5 +2306,29 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); } + public void registerActivityWatcher(IActivityWatcher watcher) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(watcher != null ? watcher.asBinder() : null); + mRemote.transact(REGISTER_ACTIVITY_WATCHER_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + + public void unregisterActivityWatcher(IActivityWatcher watcher) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(watcher != null ? watcher.asBinder() : null); + mRemote.transact(UNREGISTER_ACTIVITY_WATCHER_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 27e8fb5..f2814f2 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1090,6 +1090,7 @@ public final class ActivityThread { private static final class ActivityRecord { IBinder token; + int ident; Intent intent; Bundle state; Activity activity; @@ -1299,12 +1300,13 @@ public final class ActivityThread { // we use token to identify this activity without having to send the // activity itself back to the activity manager. (matters more with ipc) - public final void scheduleLaunchActivity(Intent intent, IBinder token, + public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) { ActivityRecord r = new ActivityRecord(); r.token = token; + r.ident = ident; r.intent = intent; r.activityInfo = info; r.state = state; @@ -2197,21 +2199,11 @@ public final class ActivityThread { } public final Activity startActivityNow(Activity parent, String id, - Intent intent, IBinder token, Bundle state) { - ActivityInfo aInfo = resolveActivityInfo(intent); - return startActivityNow(parent, id, intent, aInfo, token, state); - } - - public final Activity startActivityNow(Activity parent, String id, - Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state) { - return startActivityNow(parent, id, intent, activityInfo, token, state, null); - } - - public final Activity startActivityNow(Activity parent, String id, Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state, Object lastNonConfigurationInstance) { ActivityRecord r = new ActivityRecord(); r.token = token; + r.ident = 0; r.intent = intent; r.state = state; r.parent = parent; @@ -2335,10 +2327,10 @@ public final class ActivityThread { appContext.setOuterContext(activity); CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mConfiguration); - activity.attach(appContext, this, getInstrumentation(), r.token, app, - r.intent, r.activityInfo, title, r.parent, r.embeddedID, - r.lastNonConfigurationInstance, r.lastNonConfigurationChildInstances, - config); + activity.attach(appContext, this, getInstrumentation(), r.token, + r.ident, app, r.intent, r.activityInfo, title, r.parent, + r.embeddedID, r.lastNonConfigurationInstance, + r.lastNonConfigurationChildInstances, config); if (customIntent != null) { activity.mIntent = customIntent; diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index b052c99..a3c6325 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -119,13 +119,15 @@ public abstract class ApplicationThreadNative extends Binder data.enforceInterface(IApplicationThread.descriptor); Intent intent = Intent.CREATOR.createFromParcel(data); IBinder b = data.readStrongBinder(); + int ident = data.readInt(); ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data); Bundle state = data.readBundle(); List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR); List<Intent> pi = data.createTypedArrayList(Intent.CREATOR); boolean notResumed = data.readInt() != 0; boolean isForward = data.readInt() != 0; - scheduleLaunchActivity(intent, b, info, state, ri, pi, notResumed, isForward); + scheduleLaunchActivity(intent, b, ident, info, state, ri, pi, + notResumed, isForward); return true; } @@ -442,7 +444,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); } - public final void scheduleLaunchActivity(Intent intent, IBinder token, + public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) throws RemoteException { @@ -450,6 +452,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeInterfaceToken(IApplicationThread.descriptor); intent.writeToParcel(data, 0); data.writeStrongBinder(token); + data.writeInt(ident); info.writeToParcel(data, 0); data.writeBundle(state); data.writeTypedList(pendingResults); diff --git a/core/java/android/app/IActivityController.aidl b/core/java/android/app/IActivityController.aidl new file mode 100644 index 0000000..8f6b252 --- /dev/null +++ b/core/java/android/app/IActivityController.aidl @@ -0,0 +1,55 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.app; + +import android.content.Intent; + +/** + * Testing interface to monitor what is happening in the activity manager + * while tests are running. Not for normal application development. + * {@hide} + */ +interface IActivityController +{ + /** + * The system is trying to start an activity. Return true to allow + * it to be started as normal, or false to cancel/reject this activity. + */ + boolean activityStarting(in Intent intent, String pkg); + + /** + * The system is trying to return to an activity. Return true to allow + * it to be resumed as normal, or false to cancel/reject this activity. + */ + boolean activityResuming(String pkg); + + /** + * An application process has crashed (in Java). Return true for the + * normal error recovery (app crash dialog) to occur, false to kill + * it immediately. + */ + boolean appCrashed(String processName, int pid, String shortMsg, + String longMsg, in byte[] crashData); + + /** + * An application process is not responding. Return 0 to show the "app + * not responding" dialog, 1 to continue waiting, or -1 to kill it + * immediately. + */ + int appNotResponding(String processName, int pid, String processStats); +} diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 3ec7938..ee1b69b 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -216,7 +216,7 @@ public interface IActivityManager extends IInterface { String packageName, boolean waitForDebugger, boolean persistent) throws RemoteException; public void setAlwaysFinish(boolean enabled) throws RemoteException; - public void setActivityWatcher(IActivityWatcher watcher) + public void setActivityController(IActivityController watcher) throws RemoteException; public void enterSafeMode() throws RemoteException; @@ -257,6 +257,11 @@ public interface IActivityManager extends IInterface { public void stopAppSwitches() throws RemoteException; public void resumeAppSwitches() throws RemoteException; + public void registerActivityWatcher(IActivityWatcher watcher) + throws RemoteException; + public void unregisterActivityWatcher(IActivityWatcher watcher) + throws RemoteException; + /* * Private non-Binder interfaces */ @@ -372,7 +377,7 @@ public interface IActivityManager extends IInterface { int CHECK_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+53; int GRANT_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+54; int REVOKE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+55; - int SET_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+56; + int SET_ACTIVITY_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+56; int SHOW_WAITING_FOR_DEBUGGER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+57; int SIGNAL_PERSISTENT_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+58; int GET_RECENT_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+59; @@ -408,4 +413,6 @@ public interface IActivityManager extends IInterface { int START_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+89; int BACKUP_AGENT_CREATED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+90; int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91; + int REGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92; + int UNREGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93; } diff --git a/core/java/android/app/IActivityWatcher.aidl b/core/java/android/app/IActivityWatcher.aidl index f13a385..5d36e3f 100644 --- a/core/java/android/app/IActivityWatcher.aidl +++ b/core/java/android/app/IActivityWatcher.aidl @@ -1,6 +1,6 @@ -/* //device/java/android/android/app/IInstrumentationWatcher.aidl +/* ** -** Copyright 2007, The Android Open Source Project +** Copyright 2009, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -17,39 +17,10 @@ package android.app; -import android.content.Intent; - /** - * Testing interface to monitor what is happening in the activity manager - * while tests are running. Not for normal application development. + * Callback interface to watch the user's traversal through activities. * {@hide} */ -interface IActivityWatcher -{ - /** - * The system is trying to start an activity. Return true to allow - * it to be started as normal, or false to cancel/reject this activity. - */ - boolean activityStarting(in Intent intent, String pkg); - - /** - * The system is trying to return to an activity. Return true to allow - * it to be resumed as normal, or false to cancel/reject this activity. - */ - boolean activityResuming(String pkg); - - /** - * An application process has crashed (in Java). Return true for the - * normal error recovery (app crash dialog) to occur, false to kill - * it immediately. - */ - boolean appCrashed(String processName, int pid, String shortMsg, - String longMsg, in byte[] crashData); - - /** - * An application process is not responding. Return 0 to show the "app - * not responding" dialog, 1 to continue waiting, or -1 to kill it - * immediately. - */ - int appNotResponding(String processName, int pid, String processStats); +oneway interface IActivityWatcher { + void activityResuming(int activityId); } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index c0bc2a0..c915770 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -49,7 +49,7 @@ public interface IApplicationThread extends IInterface { void scheduleWindowVisibility(IBinder token, boolean showWindow) throws RemoteException; void scheduleResumeActivity(IBinder token, boolean isForward) throws RemoteException; void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException; - void scheduleLaunchActivity(Intent intent, IBinder token, + void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) throws RemoteException; diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl index 5b62192..84a6085 100644 --- a/core/java/android/app/ISearchManager.aidl +++ b/core/java/android/app/ISearchManager.aidl @@ -34,6 +34,7 @@ interface ISearchManager { in ComponentName launchActivity, in Bundle appSearchData, boolean globalSearch, - ISearchManagerCallback searchManagerCallback); + ISearchManagerCallback searchManagerCallback, + int ident); void stopSearch(); } diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 9f44c7e..13eb034 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -752,6 +752,9 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } public void afterTextChanged(Editable s) { + if (mSearchable == null) { + return; + } if (mSearchable.autoUrlDetect() && !mSearchAutoComplete.isPerformingCompletion()) { // The user changed the query, check if it is a URL and if so change the search // button in the soft keyboard to the 'Go' button. diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 0291882..b795a54 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -1531,6 +1531,8 @@ public class SearchManager private final Context mContext; + private int mIdent; + // package private since they are used by the inner class SearchManagerCallback /* package */ boolean mIsShowing = false; /* package */ final Handler mHandler; @@ -1546,6 +1548,13 @@ public class SearchManager ServiceManager.getService(Context.SEARCH_SERVICE)); } + /*package*/ void setIdent(int ident) { + if (mIdent != 0) { + throw new IllegalStateException("mIdent already set"); + } + mIdent = ident; + } + /** * Launch search UI. * @@ -1593,11 +1602,13 @@ public class SearchManager boolean globalSearch) { if (DBG) debug("startSearch(), mIsShowing=" + mIsShowing); if (mIsShowing) return; + if (mIdent == 0) throw new IllegalArgumentException( + "Called from outside of an Activity context"); try { mIsShowing = true; // activate the search manager and start it up! mService.startSearch(initialQuery, selectInitialQuery, launchActivity, appSearchData, - globalSearch, mSearchManagerCallback); + globalSearch, mSearchManagerCallback, mIdent); } catch (RemoteException ex) { Log.e(TAG, "startSearch() failed: " + ex); } diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index f781e0d..756f35c 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -338,6 +338,7 @@ public class SyncStorageEngine extends Handler { } reports.add(mChangeListeners.getBroadcastItem(i)); } + mChangeListeners.finishBroadcast(); } if (DEBUG) Log.v(TAG, "reportChange " + which + " to: " + reports); diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index 23c0a7b..584224f 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -50,6 +50,7 @@ public class RemoteCallbackList<E extends IInterface> { /*package*/ HashMap<IBinder, Callback> mCallbacks = new HashMap<IBinder, Callback>(); private Object[] mActiveBroadcast; + private int mBroadcastCount = -1; private boolean mKilled = false; private final class Callback implements IBinder.DeathRecipient { @@ -195,15 +196,16 @@ public class RemoteCallbackList<E extends IInterface> { * This creates a copy of the callback list, which you can retrieve items * from using {@link #getBroadcastItem}. Note that only one broadcast can * be active at a time, so you must be sure to always call this from the - * same thread (usually by scheduling with {@link Handler} or + * same thread (usually by scheduling with {@link Handler}) or * do your own synchronization. You must call {@link #finishBroadcast} * when done. * * <p>A typical loop delivering a broadcast looks like this: * * <pre> - * final int N = callbacks.beginBroadcast(); - * for (int i=0; i<N; i++) { + * int i = callbacks.beginBroadcast(); + * while (i > 0) { + * i--; * try { * callbacks.getBroadcastItem(i).somethingHappened(); * } catch (RemoteException e) { @@ -222,7 +224,12 @@ public class RemoteCallbackList<E extends IInterface> { */ public int beginBroadcast() { synchronized (mCallbacks) { - final int N = mCallbacks.size(); + if (mBroadcastCount > 0) { + throw new IllegalStateException( + "beginBroadcast() called while already in a broadcast"); + } + + final int N = mBroadcastCount = mCallbacks.size(); if (N <= 0) { return 0; } @@ -281,12 +288,19 @@ public class RemoteCallbackList<E extends IInterface> { * @see #beginBroadcast */ public void finishBroadcast() { + if (mBroadcastCount < 0) { + throw new IllegalStateException( + "finishBroadcast() called outside of a broadcast"); + } + Object[] active = mActiveBroadcast; if (active != null) { - final int N = active.length; + final int N = mBroadcastCount; for (int i=0; i<N; i++) { active[i] = null; } } + + mBroadcastCount = -1; } } diff --git a/core/java/android/server/search/SearchDialogWrapper.java b/core/java/android/server/search/SearchDialogWrapper.java index dbc1e7f..67be6a6 100644 --- a/core/java/android/server/search/SearchDialogWrapper.java +++ b/core/java/android/server/search/SearchDialogWrapper.java @@ -63,12 +63,13 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { private static final int MSG_START_SEARCH = 1; // Takes no arguments private static final int MSG_STOP_SEARCH = 2; - // Takes no arguments - private static final int MSG_ON_CONFIGURATION_CHANGED = 3; + // arg1 is activity id + private static final int MSG_ACTIVITY_RESUMING = 3; private static final String KEY_INITIAL_QUERY = "q"; private static final String KEY_LAUNCH_ACTIVITY = "a"; private static final String KEY_APP_SEARCH_DATA = "d"; + private static final String KEY_IDENT= "i"; // Context used for getting search UI resources private final Context mContext; @@ -82,9 +83,18 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { // If the search UI is visible, this is the callback for the client that showed it. ISearchManagerCallback mCallback = null; + // Identity of last activity that started search. + private int mStartedIdent = 0; + + // Identity of currently resumed activity. + private int mResumedIdent = 0; + // Allows disabling of search dialog for stress testing runs private final boolean mDisabledOnBoot; + // True if we have registered our receivers. + private boolean mReceiverRegistered; + /** * Creates a new search dialog wrapper and a search UI thread. The search dialog itself will * be created some asynchronously on the search UI thread. @@ -116,15 +126,21 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { } private void registerBroadcastReceiver() { - IntentFilter closeDialogsFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - mContext.registerReceiver(mBroadcastReceiver, closeDialogsFilter); - IntentFilter configurationChangedFilter = - new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED); - mContext.registerReceiver(mBroadcastReceiver, configurationChangedFilter); + if (!mReceiverRegistered) { + IntentFilter filter = new IntentFilter( + Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + mContext.registerReceiver(mBroadcastReceiver, filter, null, + mSearchUiThread); + mReceiverRegistered = true; + } } private void unregisterBroadcastReceiver() { - mContext.unregisterReceiver(mBroadcastReceiver); + if (mReceiverRegistered) { + mContext.unregisterReceiver(mBroadcastReceiver); + mReceiverRegistered = false; + } } /** @@ -136,10 +152,10 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { String action = intent.getAction(); if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - stopSearch(); + performStopSearch(); } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { if (DBG) debug(Intent.ACTION_CONFIGURATION_CHANGED); - onConfigurationChanged(); + performOnConfigurationChanged(); } } }; @@ -159,7 +175,8 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { final ComponentName launchActivity, final Bundle appSearchData, final boolean globalSearch, - final ISearchManagerCallback searchManagerCallback) { + final ISearchManagerCallback searchManagerCallback, + int ident) { if (DBG) debug("startSearch()"); Message msg = Message.obtain(); msg.what = MSG_START_SEARCH; @@ -170,6 +187,7 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { msgData.putString(KEY_INITIAL_QUERY, initialQuery); msgData.putParcelable(KEY_LAUNCH_ACTIVITY, launchActivity); msgData.putBundle(KEY_APP_SEARCH_DATA, appSearchData); + msgData.putInt(KEY_IDENT, ident); mSearchUiThread.sendMessage(msg); } @@ -183,12 +201,15 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { } /** - * Updates the search UI in response to a configuration change. + * Updates the currently resumed activity. * Can be called from any thread. */ - void onConfigurationChanged() { - if (DBG) debug("onConfigurationChanged()"); - mSearchUiThread.sendEmptyMessage(MSG_ON_CONFIGURATION_CHANGED); + public void activityResuming(int ident) { + if (DBG) debug("startSearch()"); + Message msg = Message.obtain(); + msg.what = MSG_ACTIVITY_RESUMING; + msg.arg1 = ident; + mSearchUiThread.sendMessage(msg); } // @@ -213,8 +234,8 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { case MSG_STOP_SEARCH: performStopSearch(); break; - case MSG_ON_CONFIGURATION_CHANGED: - performOnConfigurationChanged(); + case MSG_ACTIVITY_RESUMING: + performActivityResuming(msg.arg1); break; } } @@ -228,12 +249,27 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { Bundle appSearchData = msgData.getBundle(KEY_APP_SEARCH_DATA); boolean globalSearch = msg.arg2 != 0; ISearchManagerCallback searchManagerCallback = (ISearchManagerCallback) msg.obj; + int ident = msgData.getInt(KEY_IDENT); performStartSearch(initialQuery, selectInitialQuery, launchActivity, - appSearchData, globalSearch, searchManagerCallback); + appSearchData, globalSearch, searchManagerCallback, ident); } } + void updateDialogVisibility() { + if (mStartedIdent != 0) { + // mResumedIdent == 0 means we have just booted and the user + // hasn't yet gone anywhere. + if (mResumedIdent == 0 || mStartedIdent == mResumedIdent) { + if (DBG) Log.v(TAG, "******************* DIALOG: show"); + mSearchDialog.show(); + } else { + if (DBG) Log.v(TAG, "******************* DIALOG: hide"); + mSearchDialog.hide(); + } + } + } + /** * Actually launches the search UI. * This must be called on the search UI thread. @@ -243,7 +279,8 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { ComponentName launchActivity, Bundle appSearchData, boolean globalSearch, - ISearchManagerCallback searchManagerCallback) { + ISearchManagerCallback searchManagerCallback, + int ident) { if (DBG) debug("performStartSearch()"); if (mDisabledOnBoot) { @@ -254,8 +291,11 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { registerBroadcastReceiver(); mCallback = searchManagerCallback; + mStartedIdent = ident; + if (DBG) Log.v(TAG, "******************* DIALOG: start"); mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData, globalSearch); + updateDialogVisibility(); } /** @@ -264,7 +304,20 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { */ void performStopSearch() { if (DBG) debug("performStopSearch()"); + if (DBG) Log.v(TAG, "******************* DIALOG: cancel"); mSearchDialog.cancel(); + mStartedIdent = 0; + } + + /** + * Updates the resumed activity + * This must be called on the search UI thread. + */ + void performActivityResuming(int ident) { + if (DBG) debug("performResumingActivity(): mStartedIdent=" + + mStartedIdent + ", resuming: " + ident); + this.mResumedIdent = ident; + updateDialogVisibility(); } /** diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java index f9c0f1a..7629912 100644 --- a/core/java/android/server/search/SearchManagerService.java +++ b/core/java/android/server/search/SearchManagerService.java @@ -16,6 +16,8 @@ package android.server.search; +import android.app.ActivityManagerNative; +import android.app.IActivityWatcher; import android.app.ISearchManager; import android.app.ISearchManagerCallback; import android.app.SearchManager; @@ -26,6 +28,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; +import android.os.RemoteException; import android.util.Log; import java.util.List; @@ -71,8 +74,11 @@ public class SearchManagerService extends ISearchManager.Stub { * Initializes the list of searchable activities and the search UI. */ void initialize() { - ensureSearchablesCreated(); - ensureSearchDialogCreated(); + try { + ActivityManagerNative.getDefault().registerActivityWatcher( + mActivityWatcher); + } catch (RemoteException e) { + } } private synchronized void ensureSearchablesCreated() { @@ -126,6 +132,14 @@ public class SearchManagerService extends ISearchManager.Stub { } }; + private IActivityWatcher.Stub mActivityWatcher = new IActivityWatcher.Stub() { + public void activityResuming(int activityId) throws RemoteException { + if (DBG) Log.i("foo", "********************** resuming: " + activityId); + if (mSearchDialog == null) return; + mSearchDialog.activityResuming(activityId); + } + }; + /** * Informs all listeners that the list of searchables has been updated. */ @@ -206,13 +220,15 @@ public class SearchManagerService extends ISearchManager.Stub { ComponentName launchActivity, Bundle appSearchData, boolean globalSearch, - ISearchManagerCallback searchManagerCallback) { + ISearchManagerCallback searchManagerCallback, + int ident) { getSearchDialog().startSearch(initialQuery, selectInitialQuery, launchActivity, appSearchData, globalSearch, - searchManagerCallback); + searchManagerCallback, + ident); } /** diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index cd965fc..2da777a 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -26,6 +26,7 @@ import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.SystemClock; +import android.util.TypedValue; import android.view.MotionEvent; /** @@ -116,17 +117,19 @@ class FastScroller { mThumbDrawable.setAlpha(ScrollFade.ALPHA_MAX); } - private void useThumbDrawable(Drawable drawable) { + private void useThumbDrawable(Context context, Drawable drawable) { mThumbDrawable = drawable; - mThumbW = 64; //mCurrentThumb.getIntrinsicWidth(); - mThumbH = 52; //mCurrentThumb.getIntrinsicHeight(); + mThumbW = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + 64, context.getResources().getDisplayMetrics()); + mThumbH = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + 52, context.getResources().getDisplayMetrics()); mChangedBounds = true; } private void init(Context context) { // Get both the scrollbar states drawables final Resources res = context.getResources(); - useThumbDrawable(res.getDrawable( + useThumbDrawable(context, res.getDrawable( com.android.internal.R.drawable.scrollbar_handle_accelerated_anim2)); mOverlayDrawable = res.getDrawable( diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 85408d0..e9f8ea1 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -29,15 +29,6 @@ using namespace android; -enum CallbackMessageID { - kShutterCallback = 0, - kRawCallback = 1, - kJpegCallback = 2, - kPreviewCallback = 3, - kAutoFocusCallback = 4, - kErrorCallback = 5 -}; - struct fields_t { jfieldID context; jfieldID surface; diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java index 09bb8f9..4d25183 100755 --- a/packages/TtsService/src/android/tts/TtsService.java +++ b/packages/TtsService/src/android/tts/TtsService.java @@ -69,13 +69,15 @@ public class TtsService extends Service implements OnCompletionListener { mCallingApp = source; } - public SpeechItem(String source, long silenceTime) { + public SpeechItem(String source, long silenceTime, ArrayList<String> params) { mDuration = silenceTime; + mParams = params; mType = SILENCE; mCallingApp = source; } - public SpeechItem(String source, String text, ArrayList<String> params, int itemType, String filename) { + public SpeechItem(String source, String text, ArrayList<String> params, + int itemType, String filename) { mText = text; mParams = params; mType = itemType; @@ -117,14 +119,17 @@ public class TtsService extends Service implements OnCompletionListener { private static final String CATEGORY = "android.intent.category.TTS"; private static final String PKGNAME = "android.tts"; - private final RemoteCallbackList<android.speech.tts.ITtsCallback> mCallbacks = new RemoteCallbackList<ITtsCallback>(); - private HashMap<String, android.speech.tts.ITtsCallback> mCallbacksMap; + private final RemoteCallbackList<ITtsCallback> mCallbacks + = new RemoteCallbackList<ITtsCallback>(); + + private HashMap<String, ITtsCallback> mCallbacksMap; private Boolean mIsSpeaking; private ArrayList<SpeechItem> mSpeechQueue; private HashMap<String, SoundResource> mEarcons; private HashMap<String, SoundResource> mUtterances; private MediaPlayer mPlayer; + private SpeechItem mCurrentSpeechItem; private TtsService mSelf; private ContentResolver mResolver; @@ -152,6 +157,7 @@ public class TtsService extends Service implements OnCompletionListener { mSpeechQueue = new ArrayList<SpeechItem>(); mPlayer = null; + mCurrentSpeechItem = null; setDefaultSettings(); } @@ -401,6 +407,7 @@ public class TtsService extends Service implements OnCompletionListener { } finally { // This check is needed because finally will always run; even if the // method returns somewhere in the try block. + mCurrentSpeechItem = null; if (speechQueueAvailable) { speechQueueLock.unlock(); } @@ -409,6 +416,21 @@ public class TtsService extends Service implements OnCompletionListener { } public void onCompletion(MediaPlayer arg0) { + String callingApp = mCurrentSpeechItem.mCallingApp; + ArrayList<String> params = mCurrentSpeechItem.mParams; + String utteranceId = ""; + if (params != null){ + for (int i = 0; i < params.size() - 1; i = i + 2){ + String param = params.get(i); + if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){ + utteranceId = params.get(i+1); + } + } + } + if (utteranceId.length() > 0){ + dispatchUtteranceCompletedCallback(utteranceId, callingApp); + } + mCurrentSpeechItem = null; processSpeechQueue(); } @@ -417,21 +439,34 @@ public class TtsService extends Service implements OnCompletionListener { if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) { stop(callingApp); } - mSpeechQueue.add(new SpeechItem(callingApp, duration)); + mSpeechQueue.add(new SpeechItem(callingApp, duration, params)); if (!mIsSpeaking) { processSpeechQueue(); } return TextToSpeech.TTS_SUCCESS; } - private void silence(final long duration) { + private void silence(final SpeechItem speechItem) { class SilenceThread implements Runnable { public void run() { + String utteranceId = ""; + if (speechItem.mParams != null){ + for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){ + String param = speechItem.mParams.get(i); + if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){ + utteranceId = speechItem.mParams.get(i+1); + } + } + } try { - Thread.sleep(duration); + Thread.sleep(speechItem.mDuration); } catch (InterruptedException e) { e.printStackTrace(); } finally { + if (utteranceId.length() > 0){ + dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp); + } + mCurrentSpeechItem = null; processSpeechQueue(); } } @@ -444,9 +479,6 @@ public class TtsService extends Service implements OnCompletionListener { private void speakInternalOnly(final SpeechItem speechItem) { class SynthThread implements Runnable { public void run() { - String text = speechItem.mText; - ArrayList<String> params = speechItem.mParams; - String callingApp = speechItem.mCallingApp; boolean synthAvailable = false; String utteranceId = ""; try { @@ -459,26 +491,28 @@ public class TtsService extends Service implements OnCompletionListener { return; } int streamType = DEFAULT_STREAM_TYPE; - if (params != null){ + if (speechItem.mParams != null){ String language = ""; String country = ""; String variant = ""; - for (int i = 0; i < params.size() - 1; i = i + 2){ - String param = params.get(i); + for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){ + String param = speechItem.mParams.get(i); if (param != null) { if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_RATE)) { - setSpeechRate("", Integer.parseInt(params.get(i+1))); + setSpeechRate("", + Integer.parseInt(speechItem.mParams.get(i+1))); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_LANGUAGE)){ - language = params.get(i+1); + language = speechItem.mParams.get(i+1); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_COUNTRY)){ - country = params.get(i+1); + country = speechItem.mParams.get(i+1); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){ - variant = params.get(i+1); + variant = speechItem.mParams.get(i+1); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){ - utteranceId = params.get(i+1); + utteranceId = speechItem.mParams.get(i+1); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_STREAM)) { try { - streamType = Integer.parseInt(params.get(i + 1)); + streamType + = Integer.parseInt(speechItem.mParams.get(i + 1)); } catch (NumberFormatException e) { streamType = DEFAULT_STREAM_TYPE; } @@ -489,7 +523,7 @@ public class TtsService extends Service implements OnCompletionListener { setLanguage("", language, country, variant); } } - nativeSynth.speak(text, streamType); + nativeSynth.speak(speechItem.mText, streamType); } catch (InterruptedException e) { Log.e("TTS speakInternalOnly", "tryLock interrupted"); e.printStackTrace(); @@ -501,8 +535,9 @@ public class TtsService extends Service implements OnCompletionListener { synthesizerLock.unlock(); } if (utteranceId.length() > 0){ - dispatchUtteranceCompletedCallback(utteranceId, callingApp); + dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp); } + mCurrentSpeechItem = null; processSpeechQueue(); } } @@ -512,12 +547,12 @@ public class TtsService extends Service implements OnCompletionListener { synth.start(); } - private void synthToFileInternalOnly(final String text, - final ArrayList<String> params, final String filename) { + private void synthToFileInternalOnly(final SpeechItem speechItem) { class SynthThread implements Runnable { public void run() { - Log.i("TTS", "Synthesizing to " + filename); boolean synthAvailable = false; + String utteranceId = ""; + Log.i("TTS", "Synthesizing to " + speechItem.mFilename); try { synthAvailable = synthesizerLock.tryLock(); if (!synthAvailable) { @@ -527,21 +562,24 @@ public class TtsService extends Service implements OnCompletionListener { synth.start(); return; } - if (params != null){ + if (speechItem.mParams != null){ String language = ""; String country = ""; String variant = ""; - for (int i = 0; i < params.size() - 1; i = i + 2){ - String param = params.get(i); + for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){ + String param = speechItem.mParams.get(i); if (param != null){ if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_RATE)){ - setSpeechRate("", Integer.parseInt(params.get(i+1))); + setSpeechRate("", + Integer.parseInt(speechItem.mParams.get(i+1))); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_LANGUAGE)){ - language = params.get(i+1); + language = speechItem.mParams.get(i+1); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_COUNTRY)){ - country = params.get(i+1); + country = speechItem.mParams.get(i+1); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){ - variant = params.get(i+1); + variant = speechItem.mParams.get(i+1); + } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){ + utteranceId = speechItem.mParams.get(i+1); } } } @@ -549,7 +587,7 @@ public class TtsService extends Service implements OnCompletionListener { setLanguage("", language, country, variant); } } - nativeSynth.synthesizeToFile(text, filename); + nativeSynth.synthesizeToFile(speechItem.mText, speechItem.mFilename); } catch (InterruptedException e) { Log.e("TTS synthToFileInternalOnly", "tryLock interrupted"); e.printStackTrace(); @@ -560,6 +598,10 @@ public class TtsService extends Service implements OnCompletionListener { if (synthAvailable) { synthesizerLock.unlock(); } + if (utteranceId.length() > 0){ + dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp); + } + mCurrentSpeechItem = null; processSpeechQueue(); } } @@ -647,22 +689,21 @@ public class TtsService extends Service implements OnCompletionListener { return; } - SpeechItem currentSpeechItem = mSpeechQueue.get(0); + mCurrentSpeechItem = mSpeechQueue.get(0); mIsSpeaking = true; - SoundResource sr = getSoundResource(currentSpeechItem); + SoundResource sr = getSoundResource(mCurrentSpeechItem); // Synth speech as needed - synthesizer should call // processSpeechQueue to continue running the queue - Log.i("TTS processing: ", currentSpeechItem.mText); + Log.i("TTS processing: ", mCurrentSpeechItem.mText); if (sr == null) { - if (currentSpeechItem.mType == SpeechItem.TEXT) { - currentSpeechItem = splitCurrentTextIfNeeded(currentSpeechItem); - speakInternalOnly(currentSpeechItem); - } else if (currentSpeechItem.mType == SpeechItem.TEXT_TO_FILE) { - synthToFileInternalOnly(currentSpeechItem.mText, - currentSpeechItem.mParams, currentSpeechItem.mFilename); + if (mCurrentSpeechItem.mType == SpeechItem.TEXT) { + mCurrentSpeechItem = splitCurrentTextIfNeeded(mCurrentSpeechItem); + speakInternalOnly(mCurrentSpeechItem); + } else if (mCurrentSpeechItem.mType == SpeechItem.TEXT_TO_FILE) { + synthToFileInternalOnly(mCurrentSpeechItem); } else { // This is either silence or an earcon that was missing - silence(currentSpeechItem.mDuration); + silence(mCurrentSpeechItem); } } else { cleanUpPlayer(); @@ -696,7 +737,7 @@ public class TtsService extends Service implements OnCompletionListener { } mPlayer.setOnCompletionListener(this); try { - mPlayer.setAudioStreamType(getStreamTypeFromParams(currentSpeechItem.mParams)); + mPlayer.setAudioStreamType(getStreamTypeFromParams(mCurrentSpeechItem.mParams)); mPlayer.start(); } catch (IllegalStateException e) { mSpeechQueue.clear(); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 134ab80..442e9ce 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -32,6 +32,7 @@ import android.app.ActivityThread; import android.app.AlertDialog; import android.app.ApplicationErrorReport; import android.app.Dialog; +import android.app.IActivityController; import android.app.IActivityWatcher; import android.app.IApplicationThread; import android.app.IInstrumentationWatcher; @@ -76,6 +77,7 @@ import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -825,8 +827,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen String mOrigDebugApp = null; boolean mOrigWaitForDebugger = false; boolean mAlwaysFinishActivities = false; - IActivityWatcher mWatcher = null; + IActivityController mController = null; + final RemoteCallbackList<IActivityWatcher> mWatchers + = new RemoteCallbackList<IActivityWatcher>(); + /** * Callback of last caller to {@link #requestPss}. */ @@ -1623,7 +1628,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen /** * This is a simplified version of topRunningActivityLocked that provides a number of - * optional skip-over modes. It is intended for use with the ActivityWatcher hook only. + * optional skip-over modes. It is intended for use with the ActivityController hook only. * * @param token If non-null, any history records matching this token will be skipped. * @param taskId If non-zero, we'll attempt to skip over records with the same task ID. @@ -1728,10 +1733,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } ensurePackageDexOpt(r.intent.getComponent().getPackageName()); app.thread.scheduleLaunchActivity(new Intent(r.intent), r, + System.identityHashCode(r), r.info, r.icicle, results, newIntents, !andResume, isNextTransitionForward()); - // Update usage stats for launched activity - updateUsageStats(r, true); } catch (RemoteException e) { if (r.launchFailed) { // This is the second time we failed -- finish activity @@ -2184,6 +2188,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mHandler.sendMessage(msg); } + reportResumedActivity(next); + next.thumbnail = null; setFocusedActivityLocked(next); next.resumeKeyDispatchingLocked(); @@ -2454,6 +2460,26 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + private void reportResumedActivity(HistoryRecord r) { + //Log.i(TAG, "**** REPORT RESUME: " + r); + + final int identHash = System.identityHashCode(r); + updateUsageStats(r, true); + + int i = mWatchers.beginBroadcast(); + while (i > 0) { + i--; + IActivityWatcher w = mWatchers.getBroadcastItem(i); + if (w != null) { + try { + w.activityResuming(identHash); + } catch (RemoteException e) { + } + } + } + mWatchers.finishBroadcast(); + } + /** * Ensure that the top activity in the stack is resumed. * @@ -2642,10 +2668,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY, System.identityHashCode(next), next.task.taskId, next.shortComponentName); - updateUsageStats(next, true); next.app.thread.scheduleResumeActivity(next, isNextTransitionForward()); + pauseIfSleepingLocked(); } catch (Exception e) { @@ -3062,16 +3088,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen throw new SecurityException(msg); } - if (mWatcher != null) { + if (mController != null) { boolean abort = false; try { // The Intent we give to the watcher has the extra data // stripped off, since it can contain private information. Intent watchIntent = intent.cloneFilter(); - abort = !mWatcher.activityStarting(watchIntent, + abort = !mController.activityStarting(watchIntent, aInfo.applicationInfo.packageName); } catch (RemoteException e) { - mWatcher = null; + mController = null; } if (abort) { @@ -3968,16 +3994,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } synchronized(this) { - if (mWatcher != null) { + if (mController != null) { // Find the first activity that is not finishing. HistoryRecord next = topRunningActivityLocked(token, 0); if (next != null) { // ask watcher if this is allowed boolean resumeOK = true; try { - resumeOK = mWatcher.activityResuming(next.packageName); + resumeOK = mController.activityResuming(next.packageName); } catch (RemoteException e) { - mWatcher = null; + mController = null; } if (!resumeOK) { @@ -4469,9 +4495,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - if (mWatcher != null) { + if (mController != null) { try { - int res = mWatcher.appNotResponding(app.processName, + int res = mController.appNotResponding(app.processName, app.pid, info.toString()); if (res != 0) { if (res < 0) { @@ -4487,7 +4513,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } } catch (RemoteException e) { - mWatcher = null; + mController = null; } } @@ -6612,7 +6638,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } /** - * TODO: Add mWatcher hook + * TODO: Add mController hook */ public void moveTaskToFront(int task) { enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, @@ -6757,7 +6783,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // If we have a watcher, preflight the move before committing to it. First check // for *other* available tasks, but if none are available, then try again allowing the // current task to be selected. - if (mWatcher != null) { + if (mController != null) { HistoryRecord next = topRunningActivityLocked(null, task); if (next == null) { next = topRunningActivityLocked(null, 0); @@ -6766,9 +6792,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // ask watcher if this is allowed boolean moveOK = true; try { - moveOK = mWatcher.activityResuming(next.packageName); + moveOK = mController.activityResuming(next.packageName); } catch (RemoteException e) { - mWatcher = null; + mController = null; } if (!moveOK) { return false; @@ -7679,14 +7705,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - public void setActivityWatcher(IActivityWatcher watcher) { + public void setActivityController(IActivityController controller) { enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER, - "setActivityWatcher()"); + "setActivityController()"); synchronized (this) { - mWatcher = watcher; + mController = controller; } } + public void registerActivityWatcher(IActivityWatcher watcher) { + mWatchers.register(watcher); + } + + public void unregisterActivityWatcher(IActivityWatcher watcher) { + mWatchers.unregister(watcher); + } + public final void enterSafeMode() { synchronized(this) { // It only makes sense to do this before the system is ready @@ -8247,11 +8281,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT); } - if (mWatcher != null) { + if (mController != null) { try { String name = r != null ? r.processName : null; int pid = r != null ? r.pid : Binder.getCallingPid(); - if (!mWatcher.appCrashed(name, pid, + if (!mController.appCrashed(name, pid, shortMsg, longMsg, crashData)) { Log.w(TAG, "Force-killing crashed app " + name + " at watcher's request"); @@ -8259,7 +8293,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return 0; } } catch (RemoteException e) { - mWatcher = null; + mController = null; } } @@ -8685,7 +8719,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen + " mDebugTransient=" + mDebugTransient + " mOrigWaitForDebugger=" + mOrigWaitForDebugger); pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities - + " mWatcher=" + mWatcher); + + " mController=" + mController); } } diff --git a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java index 14d3d73..c782045 100644 --- a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java @@ -134,8 +134,8 @@ public class ActivityManagerPermissionTests extends TestCase { @SmallTest public void testSET_ACTIVITY_WATCHER() { try { - mAm.setActivityWatcher(null); - fail("IActivityManager.setActivityWatcher did not throw SecurityException as" + mAm.setActivityController(null); + fail("IActivityManager.setActivityController did not throw SecurityException as" + " expected"); } catch (SecurityException e) { // expected |