diff options
author | Hui Yu <huiyu@google.com> | 2020-03-16 18:56:21 -0700 |
---|---|---|
committer | Hui Yu <huiyu@google.com> | 2020-03-21 08:36:54 -0700 |
commit | 3dc45fbc57c664539e97bc3031337aeb9643a90e (patch) | |
tree | 2b5b2581eb96870bbcfdd77c381b2b75980331d0 | |
parent | 4846c5e3a95d4221f3667d62110a717dd9796d9b (diff) |
Update AppOps & UsageStats when app widget tapped.
When the app widget on the launcher is tapped on:
1. Update AppOps. AppOps treats the underlying app as foreground so the app can get while-in-use
permission.
2. Report a USER_INTERACTION event to UsageStats so UsageStats can
update mLastTimeUsed and mLastTimeVisible of this package.
Bug: 149043079
Test: manual test, tapped on a widget.
Change-Id: Ic8c91190881cf5dcf89f0f72cfd410b0c2e86bf6
5 files changed, 83 insertions, 19 deletions
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java index d06baed1a35d..4d73a61c972d 100644 --- a/core/java/android/app/usage/UsageStats.java +++ b/core/java/android/app/usage/UsageStats.java @@ -27,6 +27,7 @@ import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK; import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START; import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_STOP; import static android.app.usage.UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE; +import static android.app.usage.UsageEvents.Event.USER_INTERACTION; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; @@ -580,6 +581,18 @@ public final class UsageStats implements Parcelable { incrementServiceTimeUsed(timeStamp); } break; + case USER_INTERACTION: + if (hasForegroundActivity()) { + incrementTimeUsed(timeStamp); + } else { + mLastTimeUsed = timeStamp; + } + if (hasVisibleActivity()) { + incrementTimeVisible(timeStamp); + } else { + mLastTimeVisible = timeStamp; + } + break; default: break; } diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 0d461f5fa32c..844128758d7c 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -1240,4 +1240,18 @@ public class AppWidgetManager { throw e.rethrowFromSystemServer(); } } + + /** + * Note an app widget is tapped on. + * @param uid App UID. + * @param packageName App package name. + * @hide + */ + public void noteAppWidgetTapped(int uid, @NonNull String packageName) { + try { + mService.noteAppWidgetTapped(uid, packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 7f6c0d2077f1..4a27d3a0e71d 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -29,6 +29,7 @@ import android.app.Application; import android.app.PendingIntent; import android.app.RemoteInput; import android.appwidget.AppWidgetHostView; +import android.appwidget.AppWidgetManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.ContextWrapper; @@ -4130,8 +4131,18 @@ public class RemoteViews implements Parcelable, Filter { // The NEW_TASK flags are applied through the activity options and not as a part of // the call to startIntentSender() to ensure that they are consistently applied to // both mutable and immutable PendingIntents. + final IntentSender intentSender = pendingIntent.getIntentSender(); + final int uid = intentSender.getCreatorUid(); + final String packageName = intentSender.getCreatorPackage(); + if (uid != -1 && packageName != null) { + final AppWidgetManager appWidgetManager = + context.getSystemService(AppWidgetManager.class); + if (appWidgetManager != null) { + appWidgetManager.noteAppWidgetTapped(uid, packageName); + } + } context.startIntentSender( - pendingIntent.getIntentSender(), options.first, + intentSender, options.first, 0, 0, 0, options.second.toBundle()); } catch (IntentSender.SendIntentException e) { Log.e(LOG_TAG, "Cannot send pending intent: ", e); diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl index 6d1d1abd1ec4..9e09cf35bfec 100644 --- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl +++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl @@ -77,5 +77,6 @@ interface IAppWidgetService { boolean requestPinAppWidget(String packageName, in ComponentName providerComponent, in Bundle extras, in IntentSender resultIntent); boolean isRequestPinAppWidgetSupported(); + void noteAppWidgetTapped(int uid, String packageName); } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 260703db190c..8c1360cca940 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -35,6 +35,8 @@ import android.app.KeyguardManager; import android.app.PendingIntent; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetManagerInternal; import android.appwidget.AppWidgetProviderInfo; @@ -235,6 +237,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private PackageManagerInternal mPackageManagerInternal; private ActivityManagerInternal mActivityManagerInternal; private AppOpsManagerInternal mAppOpsManagerInternal; + private UsageStatsManagerInternal mUsageStatsManagerInternal; private SecurityPolicy mSecurityPolicy; @@ -278,6 +281,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku void systemServicesReady() { mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mAppOpsManagerInternal = LocalServices.getService(AppOpsManagerInternal.class); + mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class); } private void computeMaximumWidgetBitmapMemory() { @@ -879,8 +883,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku outUpdates.add(updatesMap.valueAt(j)); } } - updateAppOpsLocked(host, true); - // Reset the update counter once all the updates have been calculated host.lastWidgetUpdateSequenceNo = updateSequenceNo; return new ParceledListSlice<>(outUpdates); @@ -909,7 +911,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (host != null) { host.callbacks = null; pruneHostLocked(host); - updateAppOpsLocked(host, false); + mAppOpsManagerInternal.updateAppWidgetVisibility(host.getWidgetUids(), false); } } } @@ -3646,26 +3648,49 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return false; } - private void updateAppOpsLocked(Host host, boolean visible) { - if (visible) { - final int procState = mActivityManagerInternal.getUidProcessState(host.id.uid); + /** + * Note an app widget is tapped on. If a app widget is tapped, the underlying app is treated as + * foreground so the app can get while-in-use permission. + * + * @param uid UID of the underlying app. + * @param packageName Package name of the app. + */ + @Override + public void noteAppWidgetTapped(int uid, String packageName) { + final int callingUid = Binder.getCallingUid(); + final long ident = Binder.clearCallingIdentity(); + try { + // The launcher must be at TOP. + final int procState = mActivityManagerInternal.getUidProcessState(callingUid); if (procState > ActivityManager.PROCESS_STATE_TOP) { - // The launcher must be at TOP. return; } - } - final List<ResolveInfo> allHomeCandidates = new ArrayList<>(); - // Default launcher from package manager. - final ComponentName defaultLauncher = mPackageManagerInternal - .getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getUserId(host.id.uid)); - // The launcher must be default launcher. - if (defaultLauncher == null - || !defaultLauncher.getPackageName().equals(host.id.packageName)) { - return; + // Default launcher from package manager. + final ComponentName defaultLauncher = mPackageManagerInternal + .getDefaultHomeActivity(UserHandle.getUserId(callingUid)); + int defaultLauncherUid = 0; + try { + defaultLauncherUid = mPackageManager.getApplicationInfo( + defaultLauncher.getPackageName(), 0 , + UserHandle.getUserId(callingUid)).uid; + } catch (RemoteException e) { + Slog.e(TAG, "Failed to getApplicationInfo for package:" + + defaultLauncher.getPackageName(), e); + return; + } + // The callingUid must be default launcher uid. + if (defaultLauncherUid != callingUid) { + return; + } + final SparseArray<String> uid2PackageName = new SparseArray<String>(); + uid2PackageName.put(uid, packageName); + mAppOpsManagerInternal.updateAppWidgetVisibility(uid2PackageName, true); + mUsageStatsManagerInternal.reportEvent(packageName, UserHandle.getUserId(uid), + UsageEvents.Event.USER_INTERACTION); + } finally { + Binder.restoreCallingIdentity(ident); } - - mAppOpsManagerInternal.updateAppWidgetVisibility(host.getWidgetUids(), visible); } private final class CallbackHandler extends Handler { |