From cc52ce4bc4a7cfb28119d1949f44d1b1287936e7 Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Wed, 18 Nov 2015 16:48:00 +0000 Subject: [PATCH] Mask work widgets if work profile is in quiet mode. If a work profile is in quiet mode, mask widgets belonging to that profile with a generic RemoteView. Bug: 22541941 Change-Id: I3baa179630af497afa02b32f236d2bdaa4a75904 --- core/res/res/drawable/ic_corp_badge_off.xml | 56 +++++++++ .../work_widget_mask_view_background.xml | 20 ++++ core/res/res/layout/work_widget_mask_view.xml | 34 ++++++ core/res/res/values/symbols.xml | 5 + .../appwidget/AppWidgetServiceImpl.java | 110 +++++++++++++++++- 5 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 core/res/res/drawable/ic_corp_badge_off.xml create mode 100644 core/res/res/drawable/work_widget_mask_view_background.xml create mode 100644 core/res/res/layout/work_widget_mask_view.xml diff --git a/core/res/res/drawable/ic_corp_badge_off.xml b/core/res/res/drawable/ic_corp_badge_off.xml new file mode 100644 index 0000000000000..6799bf716d97b --- /dev/null +++ b/core/res/res/drawable/ic_corp_badge_off.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/core/res/res/drawable/work_widget_mask_view_background.xml b/core/res/res/drawable/work_widget_mask_view_background.xml new file mode 100644 index 0000000000000..17f0dbc2b91c8 --- /dev/null +++ b/core/res/res/drawable/work_widget_mask_view_background.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/core/res/res/layout/work_widget_mask_view.xml b/core/res/res/layout/work_widget_mask_view.xml new file mode 100644 index 0000000000000..ce86ddc61876b --- /dev/null +++ b/core/res/res/layout/work_widget_mask_view.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 36ba306117190..832984ea18135 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1243,6 +1243,7 @@ + @@ -2384,4 +2385,8 @@ + + + + diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 25fef1870ddaa..df18d3ea92056 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -37,6 +37,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; @@ -44,7 +45,10 @@ import android.content.pm.UserInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.Point; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -79,6 +83,7 @@ import com.android.internal.os.SomeArgs; import com.android.internal.util.FastXmlSerializer; import com.android.internal.widget.IRemoteViewsAdapterConnection; import com.android.internal.widget.IRemoteViewsFactory; +import com.android.internal.R; import com.android.server.LocalServices; import com.android.server.WidgetBackupProvider; @@ -149,6 +154,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } else if (Intent.ACTION_USER_STOPPED.equals(action)) { onUserStopped(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)); + } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { + refreshProfileWidgetsMaskedState(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, + UserHandle.USER_NULL)); + } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) { + UserHandle profile = (UserHandle)intent.getParcelableExtra(Intent.EXTRA_USER); + if (profile != null) { + refreshWidgetMaskedState(profile.getIdentifier()); + } } else { onPackageBroadcastReceived(intent, intent.getIntExtra( Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)); @@ -208,6 +221,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku mCallbackHandler = new CallbackHandler(mContext.getMainLooper()); mBackupRestoreController = new BackupRestoreController(); mSecurityPolicy = new SecurityPolicy(); + computeMaximumWidgetBitmapMemory(); registerBroadcastReceiver(); registerOnCrossProfileProvidersChangedListener(); @@ -251,8 +265,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku IntentFilter userFilter = new IntentFilter(); userFilter.addAction(Intent.ACTION_USER_STARTED); userFilter.addAction(Intent.ACTION_USER_STOPPED); + userFilter.addAction(Intent.ACTION_USER_SWITCHED); mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null); + + IntentFilter offModeFilter = new IntentFilter(); + offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED); + mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, + offModeFilter, null, null); } private void registerOnCrossProfileProvidersChangedListener() { @@ -395,6 +415,60 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } + /** + * Refresh the masked state for all profiles under the given user. + */ + private void refreshProfileWidgetsMaskedState(int userId) { + if (userId == UserHandle.USER_NULL) { + return; + } + List profiles = mUserManager.getEnabledProfiles(userId); + if (profiles != null) { + for (int i = 0; i < profiles.size(); i++) { + UserInfo user = profiles.get(i); + refreshWidgetMaskedState(user.id); + } + } + } + + /** + * Mask/unmask widgets in the given profile, depending on the quiet state of the profile. + */ + private void refreshWidgetMaskedState(int profileId) { + final long identity = Binder.clearCallingIdentity(); + try { + UserInfo user = mUserManager.getUserInfo(profileId); + if (!user.isManagedProfile()) { + return; + } + boolean shouldMask = user.isQuietModeEnabled(); + final int iconSize = (int) mContext.getResources().getDimension( + android.R.dimen.app_icon_size); + synchronized (mLock) { + final int N = mProviders.size(); + for (int i = 0; i < N; i++) { + Provider provider = mProviders.get(i); + int providerUserId = provider.getUserId(); + if (providerUserId == profileId) { + final int widgetCount = provider.widgets.size(); + for (int j = 0; j < widgetCount; j++) { + Widget widget = provider.widgets.get(j); + if (shouldMask) { + widget.replaceWithMaskedViewsLocked(mContext, iconSize); + } else { + widget.clearMaskedViewsLocked(); + } + scheduleNotifyUpdateAppWidgetLocked(widget, + widget.getEffectiveViewsLocked()); + } + } + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + private void resolveHostUidLocked(String pkg, int uid) { final int N = mHosts.size(); for (int i = 0; i < N; i++) { @@ -516,7 +590,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku for (int i = 0; i < N; i++) { Widget widget = instances.get(i); updatedIds[i] = widget.appWidgetId; - updatedViews.add(cloneIfLocalBinder(widget.views)); + updatedViews.add(cloneIfLocalBinder(widget.getEffectiveViewsLocked())); } return updatedIds; @@ -1128,7 +1202,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Binder.getCallingUid(), callingPackage); if (widget != null) { - return cloneIfLocalBinder(widget.views); + return cloneIfLocalBinder(widget.getEffectiveViewsLocked()); } return null; @@ -1554,8 +1628,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // For a full update we replace the RemoteViews completely. widget.views = views; } - - scheduleNotifyUpdateAppWidgetLocked(widget, views); + scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked()); } } @@ -3536,6 +3609,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku int restoredId; // tracking & remapping any restored state Provider provider; RemoteViews views; + RemoteViews maskedViews; Bundle options; Host host; @@ -3543,6 +3617,34 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku public String toString() { return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}'; } + + public void replaceWithMaskedViewsLocked(Context context, int iconSize) { + if (maskedViews != null) { + return; + } + maskedViews = new RemoteViews(context.getPackageName(), R.layout.work_widget_mask_view); + try { + Drawable icon = context.getPackageManager().getApplicationIcon( + provider.info.provider.getPackageName()); + final int width = iconSize; + final int height = iconSize; + Bitmap iconBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(iconBitmap); + icon.setBounds(0, 0, width, height); + icon.draw(canvas); + maskedViews.setImageViewBitmap(R.id.work_widget_app_icon, iconBitmap); + } catch (NameNotFoundException e) { + Slog.e(TAG, "Fail to get application icon", e); + } + } + + public void clearMaskedViewsLocked() { + maskedViews = null; + } + + public RemoteViews getEffectiveViewsLocked() { + return maskedViews != null ? maskedViews : views; + } } /**