Merge "Fix widget icon and tap behaviour." into nyc-dev

This commit is contained in:
Rubin Xu
2016-03-02 17:48:04 +00:00
committed by Android (Google) Code Review
4 changed files with 132 additions and 110 deletions

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<padding android:left="5dp" android:right="5dp" android:top="5dp" android:bottom="5dp"/>
<stroke android:width="1dp" android:color="#CCCCCC" />
</shape>

View File

@@ -15,20 +15,24 @@ Copyright (C) 2015 The Android Open Source Project
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/work_widget_mask_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F3374248" >
android:background="#F3374248"
android:clickable="true" >
<ImageView android:id="@+id/work_widget_app_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
android:layout_gravity="center"
android:clickable="false" />
<ImageView
<ImageView android:id="@+id/work_widget_badge_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginBottom="4dp"
android:layout_marginRight="4dp"
android:src="@drawable/ic_corp_badge_off" />
android:src="@drawable/ic_corp_badge_off"
android:clickable="false" />
</FrameLayout>

View File

@@ -2431,8 +2431,9 @@
<java-symbol type="string" name="importance_from_person" />
<java-symbol type="layout" name="work_widget_mask_view" />
<java-symbol type="id" name="work_widget_mask_frame" />
<java-symbol type="id" name="work_widget_app_icon" />
<java-symbol type="drawable" name="work_widget_mask_view_background" />
<java-symbol type="id" name="work_widget_badge_icon" />
<java-symbol type="id" name="aerr_report" />
<java-symbol type="id" name="aerr_reset" />

View File

@@ -16,9 +16,14 @@
package com.android.server.appwidget;
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
@@ -72,10 +77,12 @@ import android.util.SparseIntArray;
import android.util.TypedValue;
import android.util.Xml;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.widget.RemoteViews;
import com.android.internal.R;
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.BackgroundThread;
@@ -146,7 +153,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
if (DEBUG) {
Slog.i(TAG, "Received broadcast: " + action);
Slog.i(TAG, "Received broadcast: " + action + " on user " + userId);
}
if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
@@ -156,10 +163,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
onUserStopped(userId);
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
reloadWidgetsMaskedStateForUser(userId);
reloadWidgetsMaskedStateForGroup(userId);
} else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
synchronized (mLock) {
reloadWidgetProfileUnavailableMaskedStateLocked(userId);
reloadWidgetsMaskedState(userId);
}
} else if (Intent.ACTION_PACKAGES_SUSPENDED.equals(action)) {
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
@@ -202,6 +209,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
private final AlarmManager mAlarmManager;
private final UserManager mUserManager;
private final AppOpsManager mAppOpsManager;
private final KeyguardManager mKeyguardManager;
private final SecurityPolicy mSecurityPolicy;
@@ -223,6 +231,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mKeyguardManager = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
mSaveStateHandler = BackgroundThread.getHandler();
mCallbackHandler = new CallbackHandler(mContext.getMainLooper());
mBackupRestoreController = new BackupRestoreController();
@@ -436,48 +445,51 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
/**
* Reload all widgets' masked state for the given user and its associated profiles, including
* due to user not being available and package suspension.
* userId must be the group parent.
*/
private void reloadWidgetsMaskedStateForUser(int userId) {
if (!mUserManager.isUserUnlocked(userId) ||
isProfileWithLockedParent(userId)) {
private void reloadWidgetsMaskedStateForGroup(int userId) {
if (!mUserManager.isUserUnlocked(userId)) {
return;
}
synchronized (mLock) {
reloadWidgetPackageSuspensionMaskedStateLocked(userId);
reloadWidgetsMaskedState(userId);
List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
if (profiles != null) {
for (int i = 0; i < profiles.size(); i++) {
UserInfo user = profiles.get(i);
reloadWidgetProfileUnavailableMaskedStateLocked(user.id);
reloadWidgetPackageSuspensionMaskedStateLocked(user.id);
reloadWidgetsMaskedState(user.id);
}
}
}
}
/**
* Mask/unmask widgets in the given profile, depending on the quiet state
* or locked state of the profile.
*/
private void reloadWidgetProfileUnavailableMaskedStateLocked(int profileId) {
private void reloadWidgetsMaskedState(int userId) {
final long identity = Binder.clearCallingIdentity();
try {
if (!isProfileWithUnlockedParent(profileId)) {
return;
}
UserInfo user = mUserManager.getUserInfo(profileId);
boolean shouldMask = user.isQuietModeEnabled() ||
!mUserManager.isUserUnlocked(user.getUserHandle());
UserInfo user = mUserManager.getUserInfo(userId);
boolean lockedProfile = !mUserManager.isUserUnlocked(userId);
boolean quietProfile = user.isQuietModeEnabled();
final int N = mProviders.size();
for (int i = 0; i < N; i++) {
Provider provider = mProviders.get(i);
int providerUserId = provider.getUserId();
if (providerUserId != profileId) {
if (providerUserId != userId) {
continue;
}
if (provider.setMaskedByProfileUnavailabledLocked(shouldMask)) {
boolean changed = provider.setMaskedByLockedProfileLocked(lockedProfile);
changed |= provider.setMaskedByQuietProfileLocked(quietProfile);
try {
boolean suspended = mPackageManager.isPackageSuspendedForUser(
provider.info.provider.getPackageName(), provider.getUserId());
changed |= provider.setMaskedBySuspendedPackageLocked(suspended);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to query application info", e);
}
if (changed) {
if (provider.isMaskedLocked()) {
maskWidgetsViewsLocked(provider);
maskWidgetsViewsLocked(provider, null);
} else {
unmaskWidgetsViewsLocked(provider);
}
@@ -488,33 +500,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
/**
* Reload widget's masked state due to package suspension state.
*/
private void reloadWidgetPackageSuspensionMaskedStateLocked(int profileId) {
final int N = mProviders.size();
for (int i = 0; i < N; i++) {
Provider provider = mProviders.get(i);
int providerUserId = provider.getUserId();
if (providerUserId != profileId) {
continue;
}
try {
boolean suspended = mPackageManager.isPackageSuspendedForUser(
provider.info.provider.getPackageName(), provider.getUserId());
if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
if (provider.isMaskedLocked()) {
maskWidgetsViewsLocked(provider);
} else {
unmaskWidgetsViewsLocked(provider);
}
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to query application info", e);
}
}
}
/**
* Incrementally update the masked state due to package suspension state.
*/
@@ -535,7 +520,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
if (provider.isMaskedLocked()) {
maskWidgetsViewsLocked(provider);
maskWidgetsViewsLocked(provider, null);
} else {
unmaskWidgetsViewsLocked(provider);
}
@@ -544,14 +529,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
private Bitmap createMaskedWidgetBitmap(Provider provider) {
private Bitmap createMaskedWidgetBitmap(String providerPackage, int providerUserId) {
final long identity = Binder.clearCallingIdentity();
try {
// Load the unbadged application icon and pass it to the widget to appear on
// the masked view.
final String providerPackage = provider.info.provider.getPackageName();
Context userContext = mContext.createPackageContextAsUser(providerPackage, 0,
UserHandle.of(provider.getUserId()));
UserHandle.of(providerUserId));
PackageManager pm = userContext.getPackageManager();
Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm);
// Create a bitmap of the icon which is what the widget's remoteview requires.
@@ -566,18 +550,73 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
private void maskWidgetsViewsLocked(Provider provider) {
Bitmap iconBitmap = createMaskedWidgetBitmap(provider);
private RemoteViews createMaskedWidgetRemoteViews(Bitmap icon, boolean showBadge,
PendingIntent onClickIntent) {
RemoteViews views = new RemoteViews(mContext.getPackageName(),
R.layout.work_widget_mask_view);
if (icon != null) {
views.setImageViewBitmap(R.id.work_widget_app_icon, icon);
}
if (!showBadge) {
views.setViewVisibility(R.id.work_widget_badge_icon, View.INVISIBLE);
}
if (onClickIntent != null) {
views.setOnClickPendingIntent(R.id.work_widget_mask_frame, onClickIntent);
}
return views;
}
/**
* Mask the target widget belonging to the specified provider, or all active widgets
* of the provider if target widget == null.
*/
private void maskWidgetsViewsLocked(Provider provider, Widget targetWidget) {
final int widgetCount = provider.widgets.size();
if (widgetCount == 0) {
return;
}
final String providerPackage = provider.info.provider.getPackageName();
final int providerUserId = provider.getUserId();
Bitmap iconBitmap = createMaskedWidgetBitmap(providerPackage, providerUserId);
if (iconBitmap == null) {
return;
}
final boolean showBadge;
final Intent onClickIntent;
if (provider.maskedBySuspendedPackage) {
final long identity = Binder.clearCallingIdentity();
try {
UserInfo userInfo = mUserManager.getUserInfo(providerUserId);
showBadge = userInfo.isManagedProfile();
onClickIntent = UnlaunchableAppActivity.createPackageSuspendedDialogIntent(
providerPackage, providerUserId);
} finally {
Binder.restoreCallingIdentity(identity);
}
} else if (provider.maskedByQuietProfile) {
showBadge = true;
onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(
providerUserId);
} else /* provider.maskedByLockedProfile */ {
showBadge = true;
onClickIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null,
providerUserId);
if (onClickIntent != null) {
onClickIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
}
}
final int widgetCount = provider.widgets.size();
for (int j = 0; j < widgetCount; j++) {
Widget widget = provider.widgets.get(j);
if (widget.replaceWithMaskedViewsLocked(mContext, iconBitmap)) {
scheduleNotifyUpdateAppWidgetLocked(widget,
widget.getEffectiveViewsLocked());
if (targetWidget != null && targetWidget != widget) continue;
PendingIntent intent = null;
if (onClickIntent != null) {
intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
if (widget.replaceWithMaskedViewsLocked(views)) {
scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
}
}
}
@@ -587,8 +626,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
for (int j = 0; j < widgetCount; j++) {
Widget widget = provider.widgets.get(j);
if (widget.clearMaskedViewsLocked()) {
scheduleNotifyUpdateAppWidgetLocked(widget,
widget.getEffectiveViewsLocked());
scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
}
}
}
@@ -2472,7 +2510,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
reloadWidgetsMaskedStateForUser(userId);
reloadWidgetsMaskedStateForGroup(mSecurityPolicy.getGroupParent(userId));
final int N = mProviders.size();
for (int i = 0; i < N; i++) {
@@ -2614,10 +2652,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// If we are adding a widget it might be for a provider that
// is currently masked, if so mask the widget.
if (widget.provider.isMaskedLocked()) {
Bitmap bitmap = createMaskedWidgetBitmap(widget.provider);
if (bitmap != null) {
widget.replaceWithMaskedViewsLocked(mContext, bitmap);
}
maskWidgetsViewsLocked(widget.provider, widget);
} else {
widget.clearMaskedViewsLocked();
}
@@ -3610,7 +3645,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
PendingIntent broadcast;
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
boolean maskedByProfileUnavailable;
boolean maskedByLockedProfile;
boolean maskedByQuietProfile;
boolean maskedBySuspendedPackage;
int tag = TAG_UNDEFINED; // for use while saving state (the index)
@@ -3642,22 +3678,29 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
return "Provider{" + id + (zombie ? " Z" : "") + '}';
}
// returns true if the provider's masked state is changed as a result
public boolean setMaskedByProfileUnavailabledLocked(boolean masked) {
boolean oldMaskedState = isMaskedLocked();
maskedByProfileUnavailable = masked;
return isMaskedLocked() != oldMaskedState;
// returns true if it's different from previous state.
public boolean setMaskedByQuietProfileLocked(boolean masked) {
boolean oldState = maskedByQuietProfile;
maskedByQuietProfile = masked;
return masked != oldState;
}
// returns true if the provider's masked state is changed as a result
// returns true if it's different from previous state.
public boolean setMaskedByLockedProfileLocked(boolean masked) {
boolean oldState = maskedByLockedProfile;
maskedByLockedProfile = masked;
return masked != oldState;
}
// returns true if it's different from previous state.
public boolean setMaskedBySuspendedPackageLocked(boolean masked) {
boolean oldMaskedState = isMaskedLocked();
boolean oldState = maskedBySuspendedPackage;
maskedBySuspendedPackage = masked;
return isMaskedLocked() != oldMaskedState;
return masked != oldState;
}
public boolean isMaskedLocked() {
return maskedByProfileUnavailable || maskedBySuspendedPackage;
return maskedByQuietProfile || maskedByLockedProfile || maskedBySuspendedPackage;
}
}
@@ -3814,14 +3857,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}';
}
private boolean replaceWithMaskedViewsLocked(Context context, Bitmap icon) {
if (maskedViews != null) {
return false;
}
maskedViews = new RemoteViews(context.getPackageName(), R.layout.work_widget_mask_view);
if (icon != null) {
maskedViews.setImageViewBitmap(R.id.work_widget_app_icon, icon);
}
private boolean replaceWithMaskedViewsLocked(RemoteViews views) {
maskedViews = views;
return true;
}