Merge "Add explicit userId to AppWidget binder calls"

This commit is contained in:
Jim Miller
2013-02-21 00:00:49 +00:00
committed by Android (Google) Code Review
10 changed files with 267 additions and 264 deletions

View File

@@ -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.
*/

View File

@@ -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);

View File

@@ -2690,6 +2690,14 @@ public abstract class Context {
String packageName, int flags, UserHandle user)
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

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}
@Override
public int[] getAppWidgetIdsForHost(int hostId) throws RemoteException {
return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIdsForHost(hostId);
}
@Override
public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
getImplForUser(getCallingOrCurrentUserId()).deleteAppWidgetId(appWidgetId);
}
@Override
public void deleteHost(int hostId) throws RemoteException {
getImplForUser(getCallingOrCurrentUserId()).deleteHost(hostId);
}
@Override
public void deleteAllHosts() throws RemoteException {
getImplForUser(getCallingOrCurrentUserId()).deleteAllHosts();
}
@Override
public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options)
public int allocateAppWidgetId(String packageName, int hostId, int userId)
throws RemoteException {
getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetId(appWidgetId, provider,
options);
return getImplForUser(userId).allocateAppWidgetId(packageName, hostId);
}
@Override
public int[] getAppWidgetIdsForHost(int hostId, int userId) throws RemoteException {
return getImplForUser(userId).getAppWidgetIdsForHost(hostId);
}
@Override
public void deleteAppWidgetId(int appWidgetId, int userId) throws RemoteException {
getImplForUser(userId).deleteAppWidgetId(appWidgetId);
}
@Override
public void deleteHost(int hostId, int userId) throws RemoteException {
getImplForUser(userId).deleteHost(hostId);
}
@Override
public void deleteAllHosts(int userId) throws RemoteException {
getImplForUser(userId).deleteAllHosts();
}
@Override
public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options, int userId)
throws RemoteException {
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);
}
@Override
public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetViews(appWidgetId);
}
@Override
public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetOptions(appWidgetId, options);
}
@Override
public Bundle getAppWidgetOptions(int appWidgetId) {
return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId);
}
@Override
public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter)
public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId)
throws RemoteException {
return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders(categoryFilter);
return getImplForUser(userId).getAppWidgetInfo(appWidgetId);
}
@Override
public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
public RemoteViews getAppWidgetViews(int appWidgetId, int userId) throws RemoteException {
return getImplForUser(userId).getAppWidgetViews(appWidgetId);
}
@Override
public void updateAppWidgetOptions(int appWidgetId, Bundle options, int userId) {
getImplForUser(userId).updateAppWidgetOptions(appWidgetId, options);
}
@Override
public Bundle getAppWidgetOptions(int appWidgetId, int userId) {
return getImplForUser(userId).getAppWidgetOptions(appWidgetId);
}
@Override
public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId)
throws RemoteException {
getImplForUser(getCallingOrCurrentUserId()).notifyAppWidgetViewDataChanged(
return getImplForUser(userId).getInstalledProviders(categoryFilter);
}
@Override
public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId, int userId)
throws RemoteException {
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

View File

@@ -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

View File

@@ -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();