diff options
author | Jim Miller <jaggies@google.com> | 2013-02-21 00:00:49 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-02-21 00:00:49 +0000 |
commit | ab8e936e852b984624087c97dffc4c74b250fc68 (patch) | |
tree | 49e365cba1bd0fafb2dece3e3bd7393a65a71928 | |
parent | c94f06754a24f775072578d27eb08e4e55ddd93b (diff) | |
parent | a75a883fe9ea1790803148f0a561473073e3f264 (diff) | |
download | frameworks_base-ab8e936e852b984624087c97dffc4c74b250fc68.zip frameworks_base-ab8e936e852b984624087c97dffc4c74b250fc68.tar.gz frameworks_base-ab8e936e852b984624087c97dffc4c74b250fc68.tar.bz2 |
Merge "Add explicit userId to AppWidget binder calls"
10 files changed, 241 insertions, 238 deletions
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java index fa3bf4d..a470e70 100644 --- a/core/java/android/appwidget/AppWidgetHost.java +++ b/core/java/android/appwidget/AppWidgetHost.java @@ -31,6 +31,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.util.DisplayMetrics; +import android.util.Log; import android.util.TypedValue; import android.widget.RemoteViews; import android.widget.RemoteViews.OnClickHandler; @@ -55,38 +56,39 @@ public class AppWidgetHost { Context mContext; String mPackageName; + Handler mHandler; + int mHostId; + Callbacks mCallbacks = new Callbacks(); + final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>(); + private OnClickHandler mOnClickHandler; class Callbacks extends IAppWidgetHost.Stub { - public void updateAppWidget(int appWidgetId, RemoteViews views) { + public void updateAppWidget(int appWidgetId, RemoteViews views, int userId) { if (isLocalBinder() && views != null) { views = views.clone(); - views.setUser(mUser); + views.setUser(new UserHandle(userId)); } - Message msg = mHandler.obtainMessage(HANDLE_UPDATE); - msg.arg1 = appWidgetId; - msg.obj = views; + Message msg = mHandler.obtainMessage(HANDLE_UPDATE, appWidgetId, userId, views); msg.sendToTarget(); } - public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) { + public void providerChanged(int appWidgetId, AppWidgetProviderInfo info, int userId) { if (isLocalBinder() && info != null) { info = info.clone(); } - Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED); - msg.arg1 = appWidgetId; - msg.obj = info; + Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED, + appWidgetId, userId, info); msg.sendToTarget(); } - public void providersChanged() { - Message msg = mHandler.obtainMessage(HANDLE_PROVIDERS_CHANGED); + public void providersChanged(int userId) { + Message msg = mHandler.obtainMessage(HANDLE_PROVIDERS_CHANGED, userId, 0); msg.sendToTarget(); } - public void viewDataChanged(int appWidgetId, int viewId) { - Message msg = mHandler.obtainMessage(HANDLE_VIEW_DATA_CHANGED); - msg.arg1 = appWidgetId; - msg.arg2 = viewId; + public void viewDataChanged(int appWidgetId, int viewId, int userId) { + Message msg = mHandler.obtainMessage(HANDLE_VIEW_DATA_CHANGED, + appWidgetId, viewId, userId); msg.sendToTarget(); } } @@ -99,7 +101,7 @@ public class AppWidgetHost { public void handleMessage(Message msg) { switch (msg.what) { case HANDLE_UPDATE: { - updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj); + updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj, msg.arg2); break; } case HANDLE_PROVIDER_CHANGED: { @@ -107,26 +109,17 @@ public class AppWidgetHost { break; } case HANDLE_PROVIDERS_CHANGED: { - onProvidersChanged(); + onProvidersChanged(msg.arg1); break; } case HANDLE_VIEW_DATA_CHANGED: { - viewDataChanged(msg.arg1, msg.arg2); + viewDataChanged(msg.arg1, msg.arg2, (Integer) msg.obj); break; } } } } - Handler mHandler; - - int mHostId; - Callbacks mCallbacks = new Callbacks(); - final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>(); - private OnClickHandler mOnClickHandler; - // Optionally set by lockscreen - private UserHandle mUser; - public AppWidgetHost(Context context, int hostId) { this(context, hostId, null, context.getMainLooper()); } @@ -140,14 +133,9 @@ public class AppWidgetHost { mOnClickHandler = handler; mHandler = new UpdateHandler(looper); mDisplayMetrics = context.getResources().getDisplayMetrics(); - mUser = Process.myUserHandle(); bindService(); } - /** @hide */ - public void setUserId(int userId) { - mUser = new UserHandle(userId); - } private static void bindService() { synchronized (sServiceLock) { @@ -163,23 +151,15 @@ public class AppWidgetHost { * becomes visible, i.e. from onStart() in your Activity. */ public void startListening() { - startListeningAsUser(UserHandle.myUserId()); - } - - /** - * Start receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity - * becomes visible, i.e. from onStart() in your Activity. - * @hide - */ - public void startListeningAsUser(int userId) { int[] updatedIds; ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>(); + final int userId = mContext.getUserId(); try { if (mPackageName == null) { mPackageName = mContext.getPackageName(); } - updatedIds = sService.startListeningAsUser( + updatedIds = sService.startListening( mCallbacks, mPackageName, mHostId, updatedViews, userId); } catch (RemoteException e) { @@ -191,7 +171,7 @@ public class AppWidgetHost { if (updatedViews.get(i) != null) { updatedViews.get(i).setUser(new UserHandle(userId)); } - updateAppWidgetView(updatedIds[i], updatedViews.get(i)); + updateAppWidgetView(updatedIds[i], updatedViews.get(i), userId); } } @@ -201,26 +181,14 @@ public class AppWidgetHost { */ public void stopListening() { try { - sService.stopListeningAsUser(mHostId, UserHandle.myUserId()); + sService.stopListening(mHostId, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); } - } - /** - * Stop receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity is - * no longer visible, i.e. from onStop() in your Activity. - * @hide - */ - public void stopListeningAsUser(int userId) { - try { - sService.stopListeningAsUser(mHostId, userId); - } - catch (RemoteException e) { - throw new RuntimeException("system server dead?", e); - } - // Also clear the views + // This is here because keyguard needs it since it'll be switching users after this call. + // If it turns out other apps need to call this often, we should re-think how this works. clearViews(); } @@ -230,11 +198,12 @@ public class AppWidgetHost { * @return a appWidgetId */ public int allocateAppWidgetId() { + try { if (mPackageName == null) { mPackageName = mContext.getPackageName(); } - return sService.allocateAppWidgetId(mPackageName, mHostId); + return sService.allocateAppWidgetId(mPackageName, mHostId, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -247,7 +216,7 @@ public class AppWidgetHost { * @return a appWidgetId * @hide */ - public static int allocateAppWidgetIdForSystem(int hostId) { + public static int allocateAppWidgetIdForSystem(int hostId, int userId) { checkCallerIsSystem(); try { if (sService == null) { @@ -256,7 +225,7 @@ public class AppWidgetHost { Context systemContext = (Context) ActivityThread.currentActivityThread().getSystemContext(); String packageName = systemContext.getPackageName(); - return sService.allocateAppWidgetId(packageName, hostId); + return sService.allocateAppWidgetId(packageName, hostId, userId); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); } @@ -272,7 +241,7 @@ public class AppWidgetHost { if (sService == null) { bindService(); } - return sService.getAppWidgetIdsForHost(mHostId); + return sService.getAppWidgetIdsForHost(mHostId, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); } @@ -297,7 +266,7 @@ public class AppWidgetHost { synchronized (mViews) { mViews.remove(appWidgetId); try { - sService.deleteAppWidgetId(appWidgetId); + sService.deleteAppWidgetId(appWidgetId, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -309,13 +278,13 @@ public class AppWidgetHost { * Stop listening to changes for this AppWidget. * @hide */ - public static void deleteAppWidgetIdForSystem(int appWidgetId) { + public static void deleteAppWidgetIdForSystem(int appWidgetId, int userId) { checkCallerIsSystem(); try { if (sService == null) { bindService(); } - sService.deleteAppWidgetId(appWidgetId); + sService.deleteAppWidgetId(appWidgetId, userId); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); } @@ -331,7 +300,7 @@ public class AppWidgetHost { */ public void deleteHost() { try { - sService.deleteHost(mHostId); + sService.deleteHost(mHostId, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -347,8 +316,16 @@ public class AppWidgetHost { * </ul> */ public static void deleteAllHosts() { + deleteAllHosts(UserHandle.myUserId()); + } + + /** + * Private method containing a userId + * @hide + */ + public static void deleteAllHosts(int userId) { try { - sService.deleteAllHosts(); + sService.deleteAllHosts(userId); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -361,8 +338,9 @@ public class AppWidgetHost { */ public final AppWidgetHostView createView(Context context, int appWidgetId, AppWidgetProviderInfo appWidget) { + final int userId = context.getUserId(); AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget); - view.setUserId(mUser.getIdentifier()); + view.setUserId(userId); view.setOnClickHandler(mOnClickHandler); view.setAppWidget(appWidgetId, appWidget); synchronized (mViews) { @@ -370,9 +348,9 @@ public class AppWidgetHost { } RemoteViews views; try { - views = sService.getAppWidgetViews(appWidgetId); + views = sService.getAppWidgetViews(appWidgetId, userId); if (views != null) { - views.setUser(mUser); + views.setUser(new UserHandle(mContext.getUserId())); } } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -422,10 +400,20 @@ public class AppWidgetHost { * are added, updated or removed, or widget components are enabled or disabled.) */ protected void onProvidersChanged() { - // Do nothing + onProvidersChanged(mContext.getUserId()); } - void updateAppWidgetView(int appWidgetId, RemoteViews views) { + /** + * Private method containing a userId + * @hide + */ + protected void onProvidersChanged(int userId) { + checkUserMatch(userId); + // Does nothing + } + + void updateAppWidgetView(int appWidgetId, RemoteViews views, int userId) { + checkUserMatch(userId); AppWidgetHostView v; synchronized (mViews) { v = mViews.get(appWidgetId); @@ -435,7 +423,8 @@ public class AppWidgetHost { } } - void viewDataChanged(int appWidgetId, int viewId) { + void viewDataChanged(int appWidgetId, int viewId, int userId) { + checkUserMatch(userId); AppWidgetHostView v; synchronized (mViews) { v = mViews.get(appWidgetId); @@ -445,6 +434,16 @@ public class AppWidgetHost { } } + // Ensure that the userId passed to us agrees with the one associated with this instance + // of AppWidgetHost. + // TODO: This should be removed in production code. + private void checkUserMatch(int userId) { + if (userId != mContext.getUserId()) { + throw new IllegalStateException( + "User ids don't match, userId=" + userId + ", mUserId=" + mContext.getUserId()); + } + } + /** * Clear the list of Views that have been created by this AppWidgetHost. */ diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 6b1c3e2..e68d23a 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -16,6 +16,7 @@ package android.appwidget; +import android.app.ActivityManagerNative; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -268,8 +269,8 @@ public class AppWidgetManager { /** * Sent when the custom extras for an AppWidget change. * - * @see AppWidgetProvider#onAppWidgetOptionsChanged - * AppWidgetProvider.onAppWidgetOptionsChanged(Context context, + * @see AppWidgetProvider#onAppWidgetOptionsChanged + * AppWidgetProvider.onAppWidgetOptionsChanged(Context context, * AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras) */ public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS"; @@ -352,7 +353,7 @@ public class AppWidgetManager { * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast, * and outside of the handler. * This method will only work when called from the uid that owns the AppWidget provider. - * + * * <p> * The total Bitmap memory used by the RemoteViews object cannot exceed that required to * fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes. @@ -362,7 +363,7 @@ public class AppWidgetManager { */ public void updateAppWidget(int[] appWidgetIds, RemoteViews views) { try { - sService.updateAppWidgetIds(appWidgetIds, views); + sService.updateAppWidgetIds(appWidgetIds, views, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -382,7 +383,7 @@ public class AppWidgetManager { */ public void updateAppWidgetOptions(int appWidgetId, Bundle options) { try { - sService.updateAppWidgetOptions(appWidgetId, options); + sService.updateAppWidgetOptions(appWidgetId, options, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -402,7 +403,7 @@ public class AppWidgetManager { */ public Bundle getAppWidgetOptions(int appWidgetId) { try { - return sService.getAppWidgetOptions(appWidgetId); + return sService.getAppWidgetOptions(appWidgetId, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -436,7 +437,7 @@ public class AppWidgetManager { * Perform an incremental update or command on the widget(s) specified by appWidgetIds. * * This update differs from {@link #updateAppWidget(int[], RemoteViews)} in that the - * RemoteViews object which is passed is understood to be an incomplete representation of the + * RemoteViews object which is passed is understood to be an incomplete representation of the * widget, and hence does not replace the cached representation of the widget. As of API * level 17, the new properties set within the views objects will be appended to the cached * representation of the widget, and hence will persist. @@ -458,7 +459,7 @@ public class AppWidgetManager { */ public void partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views) { try { - sService.partiallyUpdateAppWidgetIds(appWidgetIds, views); + sService.partiallyUpdateAppWidgetIds(appWidgetIds, views, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); } @@ -507,7 +508,7 @@ public class AppWidgetManager { */ public void updateAppWidget(ComponentName provider, RemoteViews views) { try { - sService.updateAppWidgetProvider(provider, views); + sService.updateAppWidgetProvider(provider, views, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -523,7 +524,7 @@ public class AppWidgetManager { */ public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) { try { - sService.notifyAppWidgetViewDataChanged(appWidgetIds, viewId); + sService.notifyAppWidgetViewDataChanged(appWidgetIds, viewId, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -557,7 +558,8 @@ public class AppWidgetManager { */ public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) { try { - List<AppWidgetProviderInfo> providers = sService.getInstalledProviders(categoryFilter); + List<AppWidgetProviderInfo> providers = sService.getInstalledProviders(categoryFilter, + mContext.getUserId()); for (AppWidgetProviderInfo info : providers) { // Converting complex to dp. info.minWidth = @@ -584,7 +586,8 @@ public class AppWidgetManager { */ public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { try { - AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId); + AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId, + mContext.getUserId()); if (info != null) { // Converting complex to dp. info.minWidth = @@ -617,7 +620,7 @@ public class AppWidgetManager { */ public void bindAppWidgetId(int appWidgetId, ComponentName provider) { try { - sService.bindAppWidgetId(appWidgetId, provider, null); + sService.bindAppWidgetId(appWidgetId, provider, null, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -641,7 +644,7 @@ public class AppWidgetManager { */ public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) { try { - sService.bindAppWidgetId(appWidgetId, provider, options); + sService.bindAppWidgetId(appWidgetId, provider, options, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -667,7 +670,7 @@ public class AppWidgetManager { } try { return sService.bindAppWidgetIdIfAllowed( - mContext.getPackageName(), appWidgetId, provider, null); + mContext.getPackageName(), appWidgetId, provider, null, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -696,8 +699,8 @@ public class AppWidgetManager { return false; } try { - return sService.bindAppWidgetIdIfAllowed( - mContext.getPackageName(), appWidgetId, provider, options); + return sService.bindAppWidgetIdIfAllowed(mContext.getPackageName(), appWidgetId, + provider, options, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -715,7 +718,7 @@ public class AppWidgetManager { */ public boolean hasBindAppWidgetPermission(String packageName) { try { - return sService.hasBindAppWidgetPermission(packageName); + return sService.hasBindAppWidgetPermission(packageName, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -733,7 +736,7 @@ public class AppWidgetManager { */ public void setBindAppWidgetPermission(String packageName, boolean permission) { try { - sService.setBindAppWidgetPermission(packageName, permission); + sService.setBindAppWidgetPermission(packageName, permission, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); @@ -794,7 +797,7 @@ public class AppWidgetManager { */ public int[] getAppWidgetIds(ComponentName provider) { try { - return sService.getAppWidgetIds(provider); + return sService.getAppWidgetIds(provider, mContext.getUserId()); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index c964af4..8a9eed2 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2691,6 +2691,14 @@ public abstract class Context { throws PackageManager.NameNotFoundException; /** + * Get the userId associated with this context + * @return user id + * + * @hide + */ + public abstract int getUserId(); + + /** * Return a new Context object for the current Context but whose resources * are adjusted to match the given Configuration. Each call to this method * returns a new instance of a Context object; Context objects are not diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 736dd99..2f1bf8c 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -623,6 +623,12 @@ public class ContextWrapper extends Context { return mBase.createPackageContextAsUser(packageName, flags, user); } + /** @hide */ + @Override + public int getUserId() { + return mBase.getUserId(); + } + @Override public Context createConfigurationContext(Configuration overrideConfiguration) { return mBase.createConfigurationContext(overrideConfiguration); diff --git a/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl b/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl index 78b4466..6d51d38 100644 --- a/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl +++ b/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl @@ -22,9 +22,9 @@ import android.widget.RemoteViews; /** {@hide} */ oneway interface IAppWidgetHost { - void updateAppWidget(int appWidgetId, in RemoteViews views); - void providerChanged(int appWidgetId, in AppWidgetProviderInfo info); - void providersChanged(); - void viewDataChanged(int appWidgetId, int viewId); + void updateAppWidget(int appWidgetId, in RemoteViews views, int userId); + void providerChanged(int appWidgetId, in AppWidgetProviderInfo info, int userId); + void providersChanged(int userId); + void viewDataChanged(int appWidgetId, int viewId, int userId); } diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl index e685e63..7ddd5d2 100644 --- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl +++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl @@ -26,42 +26,39 @@ import android.widget.RemoteViews; /** {@hide} */ interface IAppWidgetService { - + // // for AppWidgetHost // int[] startListening(IAppWidgetHost host, String packageName, int hostId, - out List<RemoteViews> updatedViews); - int[] startListeningAsUser(IAppWidgetHost host, String packageName, int hostId, out List<RemoteViews> updatedViews, int userId); - void stopListening(int hostId); - void stopListeningAsUser(int hostId, int userId); - int allocateAppWidgetId(String packageName, int hostId); - void deleteAppWidgetId(int appWidgetId); - void deleteHost(int hostId); - void deleteAllHosts(); - RemoteViews getAppWidgetViews(int appWidgetId); - int[] getAppWidgetIdsForHost(int hostId); + void stopListening(int hostId, int userId); + int allocateAppWidgetId(String packageName, int hostId, int userId); + void deleteAppWidgetId(int appWidgetId, int userId); + void deleteHost(int hostId, int userId); + void deleteAllHosts(int userId); + RemoteViews getAppWidgetViews(int appWidgetId, int userId); + int[] getAppWidgetIdsForHost(int hostId, int userId); // // for AppWidgetManager // - void updateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views); - void updateAppWidgetOptions(int appWidgetId, in Bundle extras); - Bundle getAppWidgetOptions(int appWidgetId); - void partiallyUpdateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views); - void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views); - void notifyAppWidgetViewDataChanged(in int[] appWidgetIds, int viewId); - List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter); - AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId); - boolean hasBindAppWidgetPermission(in String packageName); - void setBindAppWidgetPermission(in String packageName, in boolean permission); - void bindAppWidgetId(int appWidgetId, in ComponentName provider, in Bundle options); - boolean bindAppWidgetIdIfAllowed( - in String packageName, int appWidgetId, in ComponentName provider, in Bundle options); + void updateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views, int userId); + void updateAppWidgetOptions(int appWidgetId, in Bundle extras, int userId); + Bundle getAppWidgetOptions(int appWidgetId, int userId); + void partiallyUpdateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views, int userId); + void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views, int userId); + void notifyAppWidgetViewDataChanged(in int[] appWidgetIds, int viewId, int userId); + List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId); + AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId); + boolean hasBindAppWidgetPermission(in String packageName, int userId); + void setBindAppWidgetPermission(in String packageName, in boolean permission, int userId); + void bindAppWidgetId(int appWidgetId, in ComponentName provider, in Bundle options, int userId); + boolean bindAppWidgetIdIfAllowed(in String packageName, int appWidgetId, + in ComponentName provider, in Bundle options, int userId); void bindRemoteViewsService(int appWidgetId, in Intent intent, in IBinder connection, int userId); void unbindRemoteViewsService(int appWidgetId, in Intent intent, int userId); - int[] getAppWidgetIds(in ComponentName provider); + int[] getAppWidgetIds(in ComponentName provider, int userId); } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java index a0a5f5a..06f06b5 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java @@ -30,6 +30,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Canvas; @@ -102,8 +103,9 @@ public class KeyguardHostView extends KeyguardViewBase { private boolean mUserSetupCompleted; - // User for whom this host view was created - private int mUserId; + // User for whom this host view was created. Final because we should never change the + // id without reconstructing an instance of KeyguardHostView. See note below... + private final int mUserId; private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView; @@ -132,10 +134,35 @@ public class KeyguardHostView extends KeyguardViewBase { public KeyguardHostView(Context context, AttributeSet attrs) { super(context, attrs); mLockPatternUtils = new LockPatternUtils(context); + + // Note: This depends on KeyguardHostView getting reconstructed every time the + // user switches, since mUserId will be used for the entire session. + // Once created, keyguard should *never* re-use this instance with another user. + // In other words, mUserId should never change - hence it's marked final. mUserId = mLockPatternUtils.getCurrentUser(); - mAppWidgetHost = new AppWidgetHost( - context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper()); - mAppWidgetHost.setUserId(mUserId); + + Context userContext = null; + try { + final String packageName = "system"; + userContext = mContext.createPackageContextAsUser(packageName, 0, + new UserHandle(mUserId)); + + } catch (NameNotFoundException e) { + e.printStackTrace(); + // This should never happen, but it's better to have no widgets than to crash. + userContext = context; + } + + // These need to be created with the user context... + mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler, + Looper.myLooper()); + mAppWidgetManager = AppWidgetManager.getInstance(userContext); + + cleanupAppWidgetIds(); + + mSecurityModel = new KeyguardSecurityModel(context); + + mViewStateManager = new KeyguardViewStateManager(this); DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); @@ -355,21 +382,17 @@ public class KeyguardHostView extends KeyguardViewBase { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - mAppWidgetHost.startListeningAsUser(mUserId); + mAppWidgetHost.startListening(); KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mAppWidgetHost.stopListeningAsUser(mUserId); + mAppWidgetHost.stopListening(); KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks); } - private AppWidgetHost getAppWidgetHost() { - return mAppWidgetHost; - } - void addWidget(AppWidgetHostView view, int pageIndex) { mAppWidgetContainer.addWidget(view, pageIndex); } @@ -1020,12 +1043,13 @@ public class KeyguardHostView extends KeyguardViewBase { private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) { AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId); if (appWidgetInfo != null) { - AppWidgetHostView view = getAppWidgetHost().createView(mContext, appId, appWidgetInfo); + AppWidgetHostView view = mAppWidgetHost.createView(mContext, appId, appWidgetInfo); addWidget(view, pageIndex); return true; } else { if (updateDbIfFailed) { - Log.w(TAG, "AppWidgetInfo for app widget id " + appId + " was null, deleting"); + Log.w(TAG, "*** AppWidgetInfo for app widget id " + appId + " was null for user" + + mUserId + ", deleting"); mAppWidgetHost.deleteAppWidgetId(appId); mLockPatternUtils.removeAppWidget(appId); } diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 06aeb29..d5715a5 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -16,7 +16,7 @@ package com.android.server; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -121,107 +121,67 @@ class AppWidgetService extends IAppWidgetService.Stub }, userFilter); } - /** - * This returns the user id of the caller, if the caller is not the system process, - * otherwise it assumes that the calls are from the lockscreen and hence are meant for the - * current user. TODO: Instead, have lockscreen make explicit calls with userId - */ - private int getCallingOrCurrentUserId() { - int callingUid = Binder.getCallingUid(); - // Also check the PID because Settings (power control widget) also runs as System UID - if (callingUid == android.os.Process.myUid() - && Binder.getCallingPid() == android.os.Process.myPid()) { - try { - return ActivityManagerNative.getDefault().getCurrentUser().id; - } catch (RemoteException re) { - return UserHandle.getUserId(callingUid); - } - } else { - return UserHandle.getUserId(callingUid); - } - } - @Override - public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException { - return getImplForUser(getCallingOrCurrentUserId()).allocateAppWidgetId( - packageName, hostId); + public int allocateAppWidgetId(String packageName, int hostId, int userId) + throws RemoteException { + return getImplForUser(userId).allocateAppWidgetId(packageName, hostId); } @Override - public int[] getAppWidgetIdsForHost(int hostId) throws RemoteException { - return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIdsForHost(hostId); + public int[] getAppWidgetIdsForHost(int hostId, int userId) throws RemoteException { + return getImplForUser(userId).getAppWidgetIdsForHost(hostId); } - + @Override - public void deleteAppWidgetId(int appWidgetId) throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).deleteAppWidgetId(appWidgetId); + public void deleteAppWidgetId(int appWidgetId, int userId) throws RemoteException { + getImplForUser(userId).deleteAppWidgetId(appWidgetId); } @Override - public void deleteHost(int hostId) throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).deleteHost(hostId); + public void deleteHost(int hostId, int userId) throws RemoteException { + getImplForUser(userId).deleteHost(hostId); } @Override - public void deleteAllHosts() throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).deleteAllHosts(); + public void deleteAllHosts(int userId) throws RemoteException { + getImplForUser(userId).deleteAllHosts(); } @Override - public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) + public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options, int userId) throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetId(appWidgetId, provider, - options); + getImplForUser(userId).bindAppWidgetId(appWidgetId, provider, options); } @Override public boolean bindAppWidgetIdIfAllowed( - String packageName, int appWidgetId, ComponentName provider, Bundle options) + String packageName, int appWidgetId, ComponentName provider, Bundle options, int userId) throws RemoteException { - return getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetIdIfAllowed( + return getImplForUser(userId).bindAppWidgetIdIfAllowed( packageName, appWidgetId, provider, options); } @Override - public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException { - return getImplForUser(getCallingOrCurrentUserId()).hasBindAppWidgetPermission( - packageName); + public boolean hasBindAppWidgetPermission(String packageName, int userId) + throws RemoteException { + return getImplForUser(userId).hasBindAppWidgetPermission(packageName); } @Override - public void setBindAppWidgetPermission(String packageName, boolean permission) + public void setBindAppWidgetPermission(String packageName, boolean permission, int userId) throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).setBindAppWidgetPermission( - packageName, permission); + getImplForUser(userId).setBindAppWidgetPermission(packageName, permission); } @Override public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection, int userId) throws RemoteException { - if (Binder.getCallingPid() != android.os.Process.myPid() - && userId != UserHandle.getCallingUserId()) { - throw new SecurityException("Call from non-system process. Calling uid = " - + Binder.getCallingUid()); - } - getImplForUser(userId).bindRemoteViewsService( - appWidgetId, intent, connection); + getImplForUser(userId).bindRemoteViewsService(appWidgetId, intent, connection); } @Override public int[] startListening(IAppWidgetHost host, String packageName, int hostId, - List<RemoteViews> updatedViews) throws RemoteException { - return getImplForUser(getCallingOrCurrentUserId()).startListening(host, - packageName, hostId, updatedViews); - } - - @Override - public int[] startListeningAsUser(IAppWidgetHost host, String packageName, int hostId, List<RemoteViews> updatedViews, int userId) throws RemoteException { - if (Binder.getCallingPid() != android.os.Process.myPid() - && userId != UserHandle.getCallingUserId()) { - throw new SecurityException("Call from non-system process. Calling uid = " - + Binder.getCallingUid()); - } return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews); } @@ -250,7 +210,19 @@ class AppWidgetService extends IAppWidgetService.Stub } } + private void checkPermission(int userId) { + int realUserId = ActivityManager.handleIncomingUser( + Binder.getCallingPid(), + Binder.getCallingUid(), + userId, + false, /* allowAll */ + true, /* requireFull */ + this.getClass().getSimpleName(), + this.getClass().getPackage().getName()); + } + private AppWidgetServiceImpl getImplForUser(int userId) { + checkPermission(userId); boolean sendInitial = false; AppWidgetServiceImpl service; synchronized (mAppWidgetServices) { @@ -272,86 +244,73 @@ class AppWidgetService extends IAppWidgetService.Stub } @Override - public int[] getAppWidgetIds(ComponentName provider) throws RemoteException { - return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIds(provider); + public int[] getAppWidgetIds(ComponentName provider, int userId) throws RemoteException { + return getImplForUser(userId).getAppWidgetIds(provider); } @Override - public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException { - return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetInfo(appWidgetId); + public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId) + throws RemoteException { + return getImplForUser(userId).getAppWidgetInfo(appWidgetId); } @Override - public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException { - return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetViews(appWidgetId); + public RemoteViews getAppWidgetViews(int appWidgetId, int userId) throws RemoteException { + return getImplForUser(userId).getAppWidgetViews(appWidgetId); } @Override - public void updateAppWidgetOptions(int appWidgetId, Bundle options) { - getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetOptions(appWidgetId, options); + public void updateAppWidgetOptions(int appWidgetId, Bundle options, int userId) { + getImplForUser(userId).updateAppWidgetOptions(appWidgetId, options); } @Override - public Bundle getAppWidgetOptions(int appWidgetId) { - return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId); + public Bundle getAppWidgetOptions(int appWidgetId, int userId) { + return getImplForUser(userId).getAppWidgetOptions(appWidgetId); } @Override - public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) + public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId) throws RemoteException { - return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders(categoryFilter); + return getImplForUser(userId).getInstalledProviders(categoryFilter); } @Override - public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) + public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId, int userId) throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).notifyAppWidgetViewDataChanged( + getImplForUser(userId).notifyAppWidgetViewDataChanged( appWidgetIds, viewId); } @Override - public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) + public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId) throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).partiallyUpdateAppWidgetIds( + getImplForUser(userId).partiallyUpdateAppWidgetIds( appWidgetIds, views); } @Override - public void stopListening(int hostId) throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).stopListening(hostId); - } - - @Override - public void stopListeningAsUser(int hostId, int userId) throws RemoteException { - if (Binder.getCallingPid() != android.os.Process.myPid() - && userId != UserHandle.getCallingUserId()) { - throw new SecurityException("Call from non-system process. Calling uid = " - + Binder.getCallingUid()); - } + public void stopListening(int hostId, int userId) throws RemoteException { getImplForUser(userId).stopListening(hostId); } @Override public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId) throws RemoteException { - if (Binder.getCallingPid() != android.os.Process.myPid() - && userId != UserHandle.getCallingUserId()) { - throw new SecurityException("Call from non-system process. Calling uid = " - + Binder.getCallingUid()); - } getImplForUser(userId).unbindRemoteViewsService( appWidgetId, intent); } @Override - public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetIds(appWidgetIds, views); + public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId) + throws RemoteException { + getImplForUser(userId).updateAppWidgetIds(appWidgetIds, views); } @Override - public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) + public void updateAppWidgetProvider(ComponentName provider, RemoteViews views, int userId) throws RemoteException { - getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetProvider(provider, views); + getImplForUser(userId).updateAppWidgetProvider(provider, views); } @Override diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java index d1829ab..6eea928 100644 --- a/services/java/com/android/server/AppWidgetServiceImpl.java +++ b/services/java/com/android/server/AppWidgetServiceImpl.java @@ -1046,7 +1046,7 @@ class AppWidgetServiceImpl { if (id.host.callbacks != null) { try { // the lock is held, but this is a oneway call - id.host.callbacks.updateAppWidget(id.appWidgetId, views); + id.host.callbacks.updateAppWidget(id.appWidgetId, views, mUserId); } catch (RemoteException e) { // It failed; remove the callback. No need to prune because // we know that this host is still referenced by this instance. @@ -1065,7 +1065,7 @@ class AppWidgetServiceImpl { if (id.host.callbacks != null) { try { // the lock is held, but this is a oneway call - id.host.callbacks.viewDataChanged(id.appWidgetId, viewId); + id.host.callbacks.viewDataChanged(id.appWidgetId, viewId, mUserId); } catch (RemoteException e) { // It failed; remove the callback. No need to prune because // we know that this host is still referenced by this instance. @@ -1934,7 +1934,8 @@ class AppWidgetServiceImpl { id.views = null; if (id.host != null && id.host.callbacks != null) { try { - id.host.callbacks.providerChanged(id.appWidgetId, p.info); + id.host.callbacks.providerChanged(id.appWidgetId, p.info, + mUserId); } catch (RemoteException ex) { // It failed; remove the callback. No need to prune because // we know that this host is still referenced by this @@ -2001,7 +2002,7 @@ class AppWidgetServiceImpl { Host host = mHosts.get(i); try { if (host.callbacks != null) { - host.callbacks.providersChanged(); + host.callbacks.providersChanged(mUserId); } } catch (RemoteException ex) { // It failed; remove the callback. No need to prune because diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index cfc6bd7..29d6e4d 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -551,6 +551,12 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } + /** {@hide} */ + @Override + public int getUserId() { + throw new UnsupportedOperationException(); + } + @Override public Context createConfigurationContext(Configuration overrideConfiguration) { throw new UnsupportedOperationException(); |