Merge "Activity interceptor dialog for suspended apps" into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
822ce4f3aa
@@ -163,6 +163,7 @@ package android {
|
|||||||
field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
|
field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
|
||||||
field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
|
field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
|
||||||
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
|
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
|
||||||
|
field public static final java.lang.String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS";
|
||||||
field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
|
field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
|
||||||
field public static final java.lang.String SERIAL_PORT = "android.permission.SERIAL_PORT";
|
field public static final java.lang.String SERIAL_PORT = "android.permission.SERIAL_PORT";
|
||||||
field public static final java.lang.String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
|
field public static final java.lang.String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
|
||||||
@@ -878,6 +879,7 @@ package android.content {
|
|||||||
field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
|
field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
|
||||||
field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
|
field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
|
||||||
field public static final java.lang.String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
|
field public static final java.lang.String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
|
||||||
|
field public static final java.lang.String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
|
||||||
field public static final deprecated java.lang.String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
|
field public static final deprecated java.lang.String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
|
||||||
field public static final java.lang.String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
|
field public static final java.lang.String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
|
||||||
field public static final java.lang.String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
|
field public static final java.lang.String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
|
||||||
|
|||||||
@@ -2155,10 +2155,10 @@ public class ApplicationPackageManager extends PackageManager {
|
|||||||
public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
|
public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
|
||||||
PersistableBundle appExtras, PersistableBundle launcherExtras,
|
PersistableBundle appExtras, PersistableBundle launcherExtras,
|
||||||
String dialogMessage) {
|
String dialogMessage) {
|
||||||
// TODO (b/75332201): Pass in the dialogMessage and use it in the interceptor dialog
|
|
||||||
try {
|
try {
|
||||||
return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
|
return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
|
||||||
launcherExtras, mContext.getOpPackageName(), mContext.getUserId());
|
launcherExtras, dialogMessage, mContext.getOpPackageName(),
|
||||||
|
mContext.getUserId());
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2281,6 +2281,28 @@ public class Intent implements Parcelable, Cloneable {
|
|||||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||||
public static final String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
|
public static final String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activity Action: Started to show more details about why an application was suspended.
|
||||||
|
*
|
||||||
|
* <p>Apps holding {@link android.Manifest.permission#SUSPEND_APPS} must declare an activity
|
||||||
|
* handling this intent and protect it with
|
||||||
|
* {@link android.Manifest.permission#SEND_SHOW_SUSPENDED_APP_DETAILS}.
|
||||||
|
*
|
||||||
|
* <p>Includes an extra {@link #EXTRA_PACKAGE_NAME} which is the name of the suspended package.
|
||||||
|
*
|
||||||
|
* <p class="note">This is a protected intent that can only be sent
|
||||||
|
* by the system.
|
||||||
|
*
|
||||||
|
* @see PackageManager#isPackageSuspended()
|
||||||
|
* @see #ACTION_PACKAGES_SUSPENDED
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@SystemApi
|
||||||
|
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
|
||||||
|
public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS =
|
||||||
|
"android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast Action: Sent to a package that has been unsuspended.
|
* Broadcast Action: Sent to a package that has been unsuspended.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -273,8 +273,8 @@ interface IPackageManager {
|
|||||||
void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
|
void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
|
||||||
|
|
||||||
String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
|
String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
|
||||||
in PersistableBundle launcherExtras, in PersistableBundle appExtras,
|
in PersistableBundle appExtras, in PersistableBundle launcherExtras,
|
||||||
String callingPackage, int userId);
|
String dialogMessage, String callingPackage, int userId);
|
||||||
|
|
||||||
boolean isPackageSuspendedForUser(String packageName, int userId);
|
boolean isPackageSuspendedForUser(String packageName, int userId);
|
||||||
|
|
||||||
|
|||||||
@@ -191,10 +191,10 @@ public abstract class PackageManagerInternal {
|
|||||||
/**
|
/**
|
||||||
* Retrieve launcher extras for a suspended package provided to the system in
|
* Retrieve launcher extras for a suspended package provided to the system in
|
||||||
* {@link PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
|
* {@link PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
|
||||||
* PersistableBundle, String)}
|
* PersistableBundle, String)}.
|
||||||
*
|
*
|
||||||
* @param packageName The package for which to return launcher extras.
|
* @param packageName The package for which to return launcher extras.
|
||||||
* @param userId The user for which to check,
|
* @param userId The user for which to check.
|
||||||
* @return The launcher extras.
|
* @return The launcher extras.
|
||||||
*
|
*
|
||||||
* @see PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
|
* @see PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
|
||||||
@@ -213,6 +213,29 @@ public abstract class PackageManagerInternal {
|
|||||||
*/
|
*/
|
||||||
public abstract boolean isPackageSuspended(String packageName, int userId);
|
public abstract boolean isPackageSuspended(String packageName, int userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the package that suspended the given package. Packages can be suspended by
|
||||||
|
* device administrators or apps holding {@link android.Manifest.permission#MANAGE_USERS} or
|
||||||
|
* {@link android.Manifest.permission#SUSPEND_APPS}.
|
||||||
|
*
|
||||||
|
* @param suspendedPackage The package that has been suspended.
|
||||||
|
* @param userId The user for which to check.
|
||||||
|
* @return Name of the package that suspended the given package. Returns {@code null} if the
|
||||||
|
* given package is not currently suspended and the platform package name - i.e.
|
||||||
|
* {@code "android"} - if the package was suspended by a device admin.
|
||||||
|
*/
|
||||||
|
public abstract String getSuspendingPackage(String suspendedPackage, int userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the dialog message to be shown to the user when they try to launch a suspended
|
||||||
|
* application.
|
||||||
|
*
|
||||||
|
* @param suspendedPackage The package that has been suspended.
|
||||||
|
* @param userId The user for which to check.
|
||||||
|
* @return The dialog message to be shown to the user.
|
||||||
|
*/
|
||||||
|
public abstract String getSuspendedDialogMessage(String suspendedPackage, int userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do a straight uid lookup for the given package/application in the given user.
|
* Do a straight uid lookup for the given package/application in the given user.
|
||||||
* @see PackageManager#getPackageUidAsUser(String, int, int)
|
* @see PackageManager#getPackageUidAsUser(String, int, int)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import android.util.ArraySet;
|
|||||||
import com.android.internal.util.ArrayUtils;
|
import com.android.internal.util.ArrayUtils;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Per-user state information about a package.
|
* Per-user state information about a package.
|
||||||
@@ -47,6 +48,7 @@ public class PackageUserState {
|
|||||||
public boolean hidden; // Is the app restricted by owner / admin
|
public boolean hidden; // Is the app restricted by owner / admin
|
||||||
public boolean suspended;
|
public boolean suspended;
|
||||||
public String suspendingPackage;
|
public String suspendingPackage;
|
||||||
|
public String dialogMessage; // Message to show when a suspended package launch attempt is made
|
||||||
public PersistableBundle suspendedAppExtras;
|
public PersistableBundle suspendedAppExtras;
|
||||||
public PersistableBundle suspendedLauncherExtras;
|
public PersistableBundle suspendedLauncherExtras;
|
||||||
public boolean instantApp;
|
public boolean instantApp;
|
||||||
@@ -82,6 +84,7 @@ public class PackageUserState {
|
|||||||
hidden = o.hidden;
|
hidden = o.hidden;
|
||||||
suspended = o.suspended;
|
suspended = o.suspended;
|
||||||
suspendingPackage = o.suspendingPackage;
|
suspendingPackage = o.suspendingPackage;
|
||||||
|
dialogMessage = o.dialogMessage;
|
||||||
suspendedAppExtras = o.suspendedAppExtras;
|
suspendedAppExtras = o.suspendedAppExtras;
|
||||||
suspendedLauncherExtras = o.suspendedLauncherExtras;
|
suspendedLauncherExtras = o.suspendedLauncherExtras;
|
||||||
instantApp = o.instantApp;
|
instantApp = o.instantApp;
|
||||||
@@ -208,6 +211,9 @@ public class PackageUserState {
|
|||||||
|| !suspendingPackage.equals(oldState.suspendingPackage)) {
|
|| !suspendingPackage.equals(oldState.suspendingPackage)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!Objects.equals(dialogMessage, oldState.dialogMessage)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!BaseBundle.kindofEquals(suspendedAppExtras,
|
if (!BaseBundle.kindofEquals(suspendedAppExtras,
|
||||||
oldState.suspendedAppExtras)) {
|
oldState.suspendedAppExtras)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
82
core/java/com/android/internal/app/SuspendedAppActivity.java
Normal file
82
core/java/com/android/internal/app/SuspendedAppActivity.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.internal.app;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.util.Slog;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
|
||||||
|
public class SuspendedAppActivity extends AlertActivity
|
||||||
|
implements DialogInterface.OnClickListener {
|
||||||
|
private static final String TAG = "SuspendedAppActivity";
|
||||||
|
|
||||||
|
public static final String EXTRA_DIALOG_MESSAGE = "SuspendedAppActivity.extra.DIALOG_MESSAGE";
|
||||||
|
public static final String EXTRA_MORE_DETAILS_INTENT =
|
||||||
|
"SuspendedAppActivity.extra.MORE_DETAILS_INTENT";
|
||||||
|
|
||||||
|
private Intent mMoreDetailsIntent;
|
||||||
|
private int mUserId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle icicle) {
|
||||||
|
Window window = getWindow();
|
||||||
|
window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
|
||||||
|
super.onCreate(icicle);
|
||||||
|
|
||||||
|
final Intent intent = getIntent();
|
||||||
|
mMoreDetailsIntent = intent.getParcelableExtra(EXTRA_MORE_DETAILS_INTENT);
|
||||||
|
mUserId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1);
|
||||||
|
if (mUserId < 0) {
|
||||||
|
Slog.wtf(TAG, "Invalid user: " + mUserId);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String dialogMessage = intent.getStringExtra(EXTRA_DIALOG_MESSAGE);
|
||||||
|
if (dialogMessage == null) {
|
||||||
|
dialogMessage = getString(R.string.app_suspended_default_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
final AlertController.AlertParams ap = mAlertParams;
|
||||||
|
ap.mTitle = getString(R.string.app_suspended_title);
|
||||||
|
ap.mMessage = String.format(getResources().getConfiguration().getLocales().get(0),
|
||||||
|
dialogMessage, intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME));
|
||||||
|
ap.mPositiveButtonText = getString(android.R.string.ok);
|
||||||
|
if (mMoreDetailsIntent != null) {
|
||||||
|
ap.mNeutralButtonText = getString(R.string.app_suspended_more_details);
|
||||||
|
}
|
||||||
|
ap.mPositiveButtonListener = ap.mNeutralButtonListener = this;
|
||||||
|
setupAlert();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
switch (which) {
|
||||||
|
case AlertDialog.BUTTON_NEUTRAL:
|
||||||
|
startActivityAsUser(mMoreDetailsIntent, UserHandle.of(mUserId));
|
||||||
|
Slog.i(TAG, "Started more details activity");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2030,6 +2030,15 @@
|
|||||||
<permission android:name="android.permission.START_ANY_ACTIVITY"
|
<permission android:name="android.permission.START_ANY_ACTIVITY"
|
||||||
android:protectionLevel="signature" />
|
android:protectionLevel="signature" />
|
||||||
|
|
||||||
|
<!-- @SystemApi Must be required by activities that handle the intent action
|
||||||
|
{@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
|
||||||
|
hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system.
|
||||||
|
<p>Not for use by third-party applications.
|
||||||
|
@hide -->
|
||||||
|
<permission android:name="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS"
|
||||||
|
android:protectionLevel="signature" />
|
||||||
|
<uses-permission android:name="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS" />
|
||||||
|
|
||||||
<!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
|
<!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
|
||||||
API is no longer supported. -->
|
API is no longer supported. -->
|
||||||
<permission android:name="android.permission.RESTART_PACKAGES"
|
<permission android:name="android.permission.RESTART_PACKAGES"
|
||||||
@@ -4116,6 +4125,12 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity android:name="com.android.internal.app.SuspendedAppActivity"
|
||||||
|
android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:process=":ui">
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity android:name="com.android.internal.app.UnlaunchableAppActivity"
|
<activity android:name="com.android.internal.app.UnlaunchableAppActivity"
|
||||||
android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
|
android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
|
|||||||
@@ -4703,6 +4703,13 @@
|
|||||||
<!-- Menu item in the locale menu [CHAR LIMIT=30] -->
|
<!-- Menu item in the locale menu [CHAR LIMIT=30] -->
|
||||||
<string name="locale_search_menu">Search</string>
|
<string name="locale_search_menu">Search</string>
|
||||||
|
|
||||||
|
<!-- Title of the dialog that is shown when the user tries to launch a suspended application [CHAR LIMIT=30] -->
|
||||||
|
<string name="app_suspended_title">Action not allowed</string>
|
||||||
|
<!-- Default message shown in the dialog that is shown when the user tries to launch a suspended application [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="app_suspended_default_message">The application <xliff:g id="app_name" example="GMail">%1$s</xliff:g> is currently disabled.</string>
|
||||||
|
<!-- Title of the button to show users more details about why the app has been suspended [CHAR LIMIT=50]-->
|
||||||
|
<string name="app_suspended_more_details">More details</string>
|
||||||
|
|
||||||
<!-- Title of a dialog. The string is asking if the user wants to turn on their work profile, which contains work apps that are managed by their employer. "Work" is an adjective. [CHAR LIMIT=30] -->
|
<!-- Title of a dialog. The string is asking if the user wants to turn on their work profile, which contains work apps that are managed by their employer. "Work" is an adjective. [CHAR LIMIT=30] -->
|
||||||
<string name="work_mode_off_title">Turn on work profile?</string>
|
<string name="work_mode_off_title">Turn on work profile?</string>
|
||||||
<!-- Text in a dialog. This string describes what will happen if a user decides to turn on their work profile. "Work profile" is used as an adjective. [CHAR LIMIT=NONE] -->
|
<!-- Text in a dialog. This string describes what will happen if a user decides to turn on their work profile. "Work profile" is used as an adjective. [CHAR LIMIT=NONE] -->
|
||||||
|
|||||||
@@ -2877,6 +2877,10 @@
|
|||||||
|
|
||||||
<java-symbol type="string" name="suspended_widget_accessibility" />
|
<java-symbol type="string" name="suspended_widget_accessibility" />
|
||||||
|
|
||||||
|
<java-symbol type="string" name="app_suspended_title" />
|
||||||
|
<java-symbol type="string" name="app_suspended_more_details" />
|
||||||
|
<java-symbol type="string" name="app_suspended_default_message" />
|
||||||
|
|
||||||
<!-- Used internally for assistant to launch activity transitions -->
|
<!-- Used internally for assistant to launch activity transitions -->
|
||||||
<java-symbol type="id" name="cross_task_transition" />
|
<java-symbol type="id" name="cross_task_transition" />
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
|||||||
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
|
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
|
||||||
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
|
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
|
||||||
|
|
||||||
|
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.ActivityOptions;
|
import android.app.ActivityOptions;
|
||||||
import android.app.AppGlobals;
|
import android.app.AppGlobals;
|
||||||
import android.app.KeyguardManager;
|
import android.app.KeyguardManager;
|
||||||
@@ -41,6 +44,7 @@ import android.content.IIntentSender;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentSender;
|
import android.content.IntentSender;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
|
import android.content.pm.PackageManagerInternal;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
@@ -51,6 +55,7 @@ import android.os.UserManager;
|
|||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.app.HarmfulAppWarningActivity;
|
import com.android.internal.app.HarmfulAppWarningActivity;
|
||||||
|
import com.android.internal.app.SuspendedAppActivity;
|
||||||
import com.android.internal.app.UnlaunchableAppActivity;
|
import com.android.internal.app.UnlaunchableAppActivity;
|
||||||
import com.android.server.LocalServices;
|
import com.android.server.LocalServices;
|
||||||
|
|
||||||
@@ -151,7 +156,7 @@ class ActivityStartInterceptor {
|
|||||||
mInTask = inTask;
|
mInTask = inTask;
|
||||||
mActivityOptions = activityOptions;
|
mActivityOptions = activityOptions;
|
||||||
|
|
||||||
if (interceptSuspendPackageIfNeed()) {
|
if (interceptSuspendedPackageIfNeeded()) {
|
||||||
// Skip the rest of interceptions as the package is suspended by device admin so
|
// Skip the rest of interceptions as the package is suspended by device admin so
|
||||||
// no user action can undo this.
|
// no user action can undo this.
|
||||||
return true;
|
return true;
|
||||||
@@ -204,12 +209,7 @@ class ActivityStartInterceptor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean interceptSuspendPackageIfNeed() {
|
private boolean interceptSuspendedByAdminPackage() {
|
||||||
// Do not intercept if the admin did not suspend the package
|
|
||||||
if (mAInfo == null || mAInfo.applicationInfo == null ||
|
|
||||||
(mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DevicePolicyManagerInternal devicePolicyManager = LocalServices
|
DevicePolicyManagerInternal devicePolicyManager = LocalServices
|
||||||
.getService(DevicePolicyManagerInternal.class);
|
.getService(DevicePolicyManagerInternal.class);
|
||||||
if (devicePolicyManager == null) {
|
if (devicePolicyManager == null) {
|
||||||
@@ -232,6 +232,55 @@ class ActivityStartInterceptor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Intent createSuspendedAppInterceptIntent(String suspendedPackage,
|
||||||
|
String suspendingPackage, String dialogMessage, int userId) {
|
||||||
|
final Intent interceptIntent = new Intent(mServiceContext, SuspendedAppActivity.class)
|
||||||
|
.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
|
||||||
|
.putExtra(SuspendedAppActivity.EXTRA_DIALOG_MESSAGE, dialogMessage)
|
||||||
|
.putExtra(Intent.EXTRA_USER_ID, userId)
|
||||||
|
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||||
|
|
||||||
|
final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS)
|
||||||
|
.setPackage(suspendingPackage);
|
||||||
|
final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
|
||||||
|
final ResolveInfo resolvedInfo = mSupervisor.resolveIntent(moreDetailsIntent, null, userId);
|
||||||
|
if (resolvedInfo != null && resolvedInfo.activityInfo != null
|
||||||
|
&& requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
|
||||||
|
moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
|
||||||
|
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
interceptIntent.putExtra(SuspendedAppActivity.EXTRA_MORE_DETAILS_INTENT,
|
||||||
|
moreDetailsIntent);
|
||||||
|
}
|
||||||
|
return interceptIntent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean interceptSuspendedPackageIfNeeded() {
|
||||||
|
// Do not intercept if the package is not suspended
|
||||||
|
if (mAInfo == null || mAInfo.applicationInfo == null ||
|
||||||
|
(mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked();
|
||||||
|
if (pmi == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final String suspendedPackage = mAInfo.applicationInfo.packageName;
|
||||||
|
final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId);
|
||||||
|
if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
|
||||||
|
return interceptSuspendedByAdminPackage();
|
||||||
|
}
|
||||||
|
final String dialogMessage = pmi.getSuspendedDialogMessage(suspendedPackage, mUserId);
|
||||||
|
mIntent = createSuspendedAppInterceptIntent(suspendedPackage, suspendingPackage,
|
||||||
|
dialogMessage, mUserId);
|
||||||
|
mCallingPid = mRealCallingPid;
|
||||||
|
mCallingUid = mRealCallingUid;
|
||||||
|
mResolvedType = null;
|
||||||
|
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, 0);
|
||||||
|
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean interceptWorkProfileChallengeIfNeeded() {
|
private boolean interceptWorkProfileChallengeIfNeeded() {
|
||||||
final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId);
|
final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId);
|
||||||
if (interceptingIntent == null) {
|
if (interceptingIntent == null) {
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ import com.android.internal.R;
|
|||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.app.IMediaContainerService;
|
import com.android.internal.app.IMediaContainerService;
|
||||||
import com.android.internal.app.ResolverActivity;
|
import com.android.internal.app.ResolverActivity;
|
||||||
|
import com.android.internal.app.SuspendedAppActivity;
|
||||||
import com.android.internal.content.NativeLibraryHelper;
|
import com.android.internal.content.NativeLibraryHelper;
|
||||||
import com.android.internal.content.PackageHelper;
|
import com.android.internal.content.PackageHelper;
|
||||||
import com.android.internal.logging.MetricsLogger;
|
import com.android.internal.logging.MetricsLogger;
|
||||||
@@ -14006,8 +14007,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
|
public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
|
||||||
PersistableBundle appExtras, PersistableBundle launcherExtras, String callingPackage,
|
PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage,
|
||||||
int userId) {
|
String callingPackage, int userId) {
|
||||||
try {
|
try {
|
||||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS, null);
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS, null);
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
@@ -14055,7 +14056,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
unactionedPackages.add(packageName);
|
unactionedPackages.add(packageName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pkgSetting.setSuspended(suspended, callingPackage, appExtras,
|
pkgSetting.setSuspended(suspended, callingPackage, dialogMessage, appExtras,
|
||||||
launcherExtras, userId);
|
launcherExtras, userId);
|
||||||
changedPackagesList.add(packageName);
|
changedPackagesList.add(packageName);
|
||||||
}
|
}
|
||||||
@@ -14177,7 +14178,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
for (int user : userIds) {
|
for (int user : userIds) {
|
||||||
final PackageUserState pus = ps.readUserState(user);
|
final PackageUserState pus = ps.readUserState(user);
|
||||||
if (pus.suspended && packageName.equals(pus.suspendingPackage)) {
|
if (pus.suspended && packageName.equals(pus.suspendingPackage)) {
|
||||||
ps.setSuspended(false, null, null, null, user);
|
ps.setSuspended(false, null, null, null, null, user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18911,6 +18912,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
false /*hidden*/,
|
false /*hidden*/,
|
||||||
false /*suspended*/,
|
false /*suspended*/,
|
||||||
null, /*suspendingPackage*/
|
null, /*suspendingPackage*/
|
||||||
|
null, /*dialogMessage*/
|
||||||
null, /*suspendedAppExtras*/
|
null, /*suspendedAppExtras*/
|
||||||
null, /*suspendedLauncherExtras*/
|
null, /*suspendedLauncherExtras*/
|
||||||
false /*instantApp*/,
|
false /*instantApp*/,
|
||||||
@@ -23802,6 +23804,22 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSuspendingPackage(String suspendedPackage, int userId) {
|
||||||
|
synchronized (mPackages) {
|
||||||
|
final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
|
||||||
|
return (ps != null) ? ps.readUserState(userId).suspendingPackage : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSuspendedDialogMessage(String suspendedPackage, int userId) {
|
||||||
|
synchronized (mPackages) {
|
||||||
|
final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
|
||||||
|
return (ps != null) ? ps.readUserState(userId).dialogMessage : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPackageUid(String packageName, int flags, int userId) {
|
public int getPackageUid(String packageName, int flags, int userId) {
|
||||||
return PackageManagerService.this
|
return PackageManagerService.this
|
||||||
|
|||||||
@@ -1505,6 +1505,7 @@ class PackageManagerShellCommand extends ShellCommand {
|
|||||||
private int runSuspend(boolean suspendedState) {
|
private int runSuspend(boolean suspendedState) {
|
||||||
final PrintWriter pw = getOutPrintWriter();
|
final PrintWriter pw = getOutPrintWriter();
|
||||||
int userId = UserHandle.USER_SYSTEM;
|
int userId = UserHandle.USER_SYSTEM;
|
||||||
|
String dialogMessage = null;
|
||||||
final PersistableBundle appExtras = new PersistableBundle();
|
final PersistableBundle appExtras = new PersistableBundle();
|
||||||
final PersistableBundle launcherExtras = new PersistableBundle();
|
final PersistableBundle launcherExtras = new PersistableBundle();
|
||||||
String opt;
|
String opt;
|
||||||
@@ -1513,6 +1514,9 @@ class PackageManagerShellCommand extends ShellCommand {
|
|||||||
case "--user":
|
case "--user":
|
||||||
userId = UserHandle.parseUserArg(getNextArgRequired());
|
userId = UserHandle.parseUserArg(getNextArgRequired());
|
||||||
break;
|
break;
|
||||||
|
case "--dialogMessage":
|
||||||
|
dialogMessage = getNextArgRequired();
|
||||||
|
break;
|
||||||
case "--ael":
|
case "--ael":
|
||||||
case "--aes":
|
case "--aes":
|
||||||
case "--aed":
|
case "--aed":
|
||||||
@@ -1553,7 +1557,7 @@ class PackageManagerShellCommand extends ShellCommand {
|
|||||||
(Binder.getCallingUid() == Process.ROOT_UID) ? "root" : "com.android.shell";
|
(Binder.getCallingUid() == Process.ROOT_UID) ? "root" : "com.android.shell";
|
||||||
try {
|
try {
|
||||||
mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
|
mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
|
||||||
appExtras, launcherExtras, callingPackage, userId);
|
appExtras, launcherExtras, dialogMessage, callingPackage, userId);
|
||||||
pw.println("Package " + packageName + " new suspended state: "
|
pw.println("Package " + packageName + " new suspended state: "
|
||||||
+ mInterface.isPackageSuspendedForUser(packageName, userId));
|
+ mInterface.isPackageSuspendedForUser(packageName, userId));
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -398,11 +398,12 @@ public abstract class PackageSettingBase extends SettingBase {
|
|||||||
return readUserState(userId).suspended;
|
return readUserState(userId).suspended;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSuspended(boolean suspended, String suspendingPackage, PersistableBundle appExtras,
|
void setSuspended(boolean suspended, String suspendingPackage, String dialogMessage,
|
||||||
PersistableBundle launcherExtras, int userId) {
|
PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
|
||||||
final PackageUserState existingUserState = modifyUserState(userId);
|
final PackageUserState existingUserState = modifyUserState(userId);
|
||||||
existingUserState.suspended = suspended;
|
existingUserState.suspended = suspended;
|
||||||
existingUserState.suspendingPackage = suspended ? suspendingPackage : null;
|
existingUserState.suspendingPackage = suspended ? suspendingPackage : null;
|
||||||
|
existingUserState.dialogMessage = suspended ? dialogMessage : null;
|
||||||
existingUserState.suspendedAppExtras = suspended ? appExtras : null;
|
existingUserState.suspendedAppExtras = suspended ? appExtras : null;
|
||||||
existingUserState.suspendedLauncherExtras = suspended ? launcherExtras : null;
|
existingUserState.suspendedLauncherExtras = suspended ? launcherExtras : null;
|
||||||
}
|
}
|
||||||
@@ -425,8 +426,8 @@ public abstract class PackageSettingBase extends SettingBase {
|
|||||||
|
|
||||||
void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
|
void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
|
||||||
boolean notLaunched, boolean hidden, boolean suspended, String suspendingPackage,
|
boolean notLaunched, boolean hidden, boolean suspended, String suspendingPackage,
|
||||||
PersistableBundle suspendedAppExtras, PersistableBundle suspendedLauncherExtras,
|
String dialogMessage, PersistableBundle suspendedAppExtras,
|
||||||
boolean instantApp,
|
PersistableBundle suspendedLauncherExtras, boolean instantApp,
|
||||||
boolean virtualPreload, String lastDisableAppCaller,
|
boolean virtualPreload, String lastDisableAppCaller,
|
||||||
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
|
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
|
||||||
int domainVerifState, int linkGeneration, int installReason,
|
int domainVerifState, int linkGeneration, int installReason,
|
||||||
@@ -440,6 +441,7 @@ public abstract class PackageSettingBase extends SettingBase {
|
|||||||
state.hidden = hidden;
|
state.hidden = hidden;
|
||||||
state.suspended = suspended;
|
state.suspended = suspended;
|
||||||
state.suspendingPackage = suspendingPackage;
|
state.suspendingPackage = suspendingPackage;
|
||||||
|
state.dialogMessage = dialogMessage;
|
||||||
state.suspendedAppExtras = suspendedAppExtras;
|
state.suspendedAppExtras = suspendedAppExtras;
|
||||||
state.suspendedLauncherExtras = suspendedLauncherExtras;
|
state.suspendedLauncherExtras = suspendedLauncherExtras;
|
||||||
state.lastDisableAppCaller = lastDisableAppCaller;
|
state.lastDisableAppCaller = lastDisableAppCaller;
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ public final class Settings {
|
|||||||
private static final String ATTR_HIDDEN = "hidden";
|
private static final String ATTR_HIDDEN = "hidden";
|
||||||
private static final String ATTR_SUSPENDED = "suspended";
|
private static final String ATTR_SUSPENDED = "suspended";
|
||||||
private static final String ATTR_SUSPENDING_PACKAGE = "suspending-package";
|
private static final String ATTR_SUSPENDING_PACKAGE = "suspending-package";
|
||||||
|
private static final String ATTR_SUSPEND_DIALOG_MESSAGE = "suspend_dialog_message";
|
||||||
// Legacy, uninstall blocks are stored separately.
|
// Legacy, uninstall blocks are stored separately.
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
|
private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
|
||||||
@@ -734,6 +735,7 @@ public final class Settings {
|
|||||||
false /*hidden*/,
|
false /*hidden*/,
|
||||||
false /*suspended*/,
|
false /*suspended*/,
|
||||||
null, /*suspendingPackage*/
|
null, /*suspendingPackage*/
|
||||||
|
null, /*dialogMessage*/
|
||||||
null, /*suspendedAppExtras*/
|
null, /*suspendedAppExtras*/
|
||||||
null, /*suspendedLauncherExtras*/
|
null, /*suspendedLauncherExtras*/
|
||||||
instantApp,
|
instantApp,
|
||||||
@@ -1628,6 +1630,7 @@ public final class Settings {
|
|||||||
false /*hidden*/,
|
false /*hidden*/,
|
||||||
false /*suspended*/,
|
false /*suspended*/,
|
||||||
null, /*suspendingPackage*/
|
null, /*suspendingPackage*/
|
||||||
|
null, /*dialogMessage*/
|
||||||
null, /*suspendedAppExtras*/
|
null, /*suspendedAppExtras*/
|
||||||
null, /*suspendedLauncherExtras*/
|
null, /*suspendedLauncherExtras*/
|
||||||
false /*instantApp*/,
|
false /*instantApp*/,
|
||||||
@@ -1704,6 +1707,8 @@ public final class Settings {
|
|||||||
false);
|
false);
|
||||||
String suspendingPackage = parser.getAttributeValue(null,
|
String suspendingPackage = parser.getAttributeValue(null,
|
||||||
ATTR_SUSPENDING_PACKAGE);
|
ATTR_SUSPENDING_PACKAGE);
|
||||||
|
final String dialogMessage = parser.getAttributeValue(null,
|
||||||
|
ATTR_SUSPEND_DIALOG_MESSAGE);
|
||||||
if (suspended && suspendingPackage == null) {
|
if (suspended && suspendingPackage == null) {
|
||||||
suspendingPackage = PLATFORM_PACKAGE_NAME;
|
suspendingPackage = PLATFORM_PACKAGE_NAME;
|
||||||
}
|
}
|
||||||
@@ -1767,7 +1772,7 @@ public final class Settings {
|
|||||||
setBlockUninstallLPw(userId, name, true);
|
setBlockUninstallLPw(userId, name, true);
|
||||||
}
|
}
|
||||||
ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
|
ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
|
||||||
hidden, suspended, suspendingPackage, suspendedAppExtras,
|
hidden, suspended, suspendingPackage, dialogMessage, suspendedAppExtras,
|
||||||
suspendedLauncherExtras, instantApp, virtualPreload, enabledCaller,
|
suspendedLauncherExtras, instantApp, virtualPreload, enabledCaller,
|
||||||
enabledComponents, disabledComponents, verifState, linkGeneration,
|
enabledComponents, disabledComponents, verifState, linkGeneration,
|
||||||
installReason, harmfulAppWarning);
|
installReason, harmfulAppWarning);
|
||||||
@@ -2077,7 +2082,14 @@ public final class Settings {
|
|||||||
}
|
}
|
||||||
if (ustate.suspended) {
|
if (ustate.suspended) {
|
||||||
serializer.attribute(null, ATTR_SUSPENDED, "true");
|
serializer.attribute(null, ATTR_SUSPENDED, "true");
|
||||||
serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, ustate.suspendingPackage);
|
if (ustate.suspendingPackage != null) {
|
||||||
|
serializer.attribute(null, ATTR_SUSPENDING_PACKAGE,
|
||||||
|
ustate.suspendingPackage);
|
||||||
|
}
|
||||||
|
if (ustate.dialogMessage != null) {
|
||||||
|
serializer.attribute(null, ATTR_SUSPEND_DIALOG_MESSAGE,
|
||||||
|
ustate.dialogMessage);
|
||||||
|
}
|
||||||
if (ustate.suspendedAppExtras != null) {
|
if (ustate.suspendedAppExtras != null) {
|
||||||
serializer.startTag(null, TAG_SUSPENDED_APP_EXTRAS);
|
serializer.startTag(null, TAG_SUSPENDED_APP_EXTRAS);
|
||||||
try {
|
try {
|
||||||
@@ -4750,8 +4762,11 @@ public final class Settings {
|
|||||||
pw.print(" suspended=");
|
pw.print(" suspended=");
|
||||||
pw.print(ps.getSuspended(user.id));
|
pw.print(ps.getSuspended(user.id));
|
||||||
if (ps.getSuspended(user.id)) {
|
if (ps.getSuspended(user.id)) {
|
||||||
|
final PackageUserState pus = ps.readUserState(user.id);
|
||||||
pw.print(" suspendingPackage=");
|
pw.print(" suspendingPackage=");
|
||||||
pw.print(ps.readUserState(user.id).suspendingPackage);
|
pw.print(pus.suspendingPackage);
|
||||||
|
pw.print(" dialogMessage=");
|
||||||
|
pw.print(pus.dialogMessage);
|
||||||
}
|
}
|
||||||
pw.print(" stopped=");
|
pw.print(" stopped=");
|
||||||
pw.print(ps.getStopped(user.id));
|
pw.print(ps.getStopped(user.id));
|
||||||
|
|||||||
@@ -9193,7 +9193,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
|||||||
long id = mInjector.binderClearCallingIdentity();
|
long id = mInjector.binderClearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
return mIPackageManager.setPackagesSuspendedAsUser(
|
return mIPackageManager.setPackagesSuspendedAsUser(
|
||||||
packageNames, suspended, null, null, "android", callingUserId);
|
packageNames, suspended, null, null, null, "android", callingUserId);
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
// Shouldn't happen.
|
// Shouldn't happen.
|
||||||
Slog.e(LOG_TAG, "Failed talking to the package manager", re);
|
Slog.e(LOG_TAG, "Failed talking to the package manager", re);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
|
|||||||
truth-prebuilt \
|
truth-prebuilt \
|
||||||
testables \
|
testables \
|
||||||
testng \
|
testng \
|
||||||
|
ub-uiautomator\
|
||||||
platformprotosnano
|
platformprotosnano
|
||||||
|
|
||||||
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
|
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
|
||||||
@@ -69,8 +70,6 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
|||||||
LOCAL_JACK_FLAGS := --multi-dex native
|
LOCAL_JACK_FLAGS := --multi-dex native
|
||||||
LOCAL_DX_FLAGS := --multi-dex
|
LOCAL_DX_FLAGS := --multi-dex
|
||||||
|
|
||||||
LOCAL_STATIC_JAVA_LIBRARIES += ub-uiautomator
|
|
||||||
|
|
||||||
LOCAL_PROGUARD_ENABLED := disabled
|
LOCAL_PROGUARD_ENABLED := disabled
|
||||||
|
|
||||||
include $(BUILD_PACKAGE)
|
include $(BUILD_PACKAGE)
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
<uses-permission android:name="android.permission.WATCH_APPOPS" />
|
<uses-permission android:name="android.permission.WATCH_APPOPS" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||||
<uses-permission android:name="android.permission.SUSPEND_APPS"/>
|
<uses-permission android:name="android.permission.SUSPEND_APPS"/>
|
||||||
|
<uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
|
||||||
|
|
||||||
<!-- Uses API introduced in O (26) -->
|
<!-- Uses API introduced in O (26) -->
|
||||||
<uses-sdk android:minSdkVersion="1"
|
<uses-sdk android:minSdkVersion="1"
|
||||||
@@ -145,6 +146,15 @@
|
|||||||
<activity android:name="com.android.server.pm.ShortcutTestActivity"
|
<activity android:name="com.android.server.pm.ShortcutTestActivity"
|
||||||
android:enabled="true" android:exported="true" />
|
android:enabled="true" android:exported="true" />
|
||||||
|
|
||||||
|
<activity android:name="com.android.server.pm.SuspendedDetailsActivity"
|
||||||
|
android:enabled="true"
|
||||||
|
android:permission="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SHOW_SUSPENDED_APP_DETAILS" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity android:name="com.android.server.accounts.AccountAuthenticatorDummyActivity" />
|
<activity android:name="com.android.server.accounts.AccountAuthenticatorDummyActivity" />
|
||||||
|
|
||||||
<activity-alias android:name="a.ShortcutEnabled"
|
<activity-alias android:name="a.ShortcutEnabled"
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
package com.android.server.am;
|
package com.android.server.am;
|
||||||
|
|
||||||
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
|
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
|
||||||
|
|
||||||
|
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -30,6 +33,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManagerInternal;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
@@ -79,6 +83,8 @@ public class ActivityStartInterceptorTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private DevicePolicyManagerInternal mDevicePolicyManager;
|
private DevicePolicyManagerInternal mDevicePolicyManager;
|
||||||
@Mock
|
@Mock
|
||||||
|
private PackageManagerInternal mPackageManagerInternal;
|
||||||
|
@Mock
|
||||||
private UserManager mUserManager;
|
private UserManager mUserManager;
|
||||||
@Mock
|
@Mock
|
||||||
private UserController mUserController;
|
private UserController mUserController;
|
||||||
@@ -103,6 +109,7 @@ public class ActivityStartInterceptorTest {
|
|||||||
when(mDevicePolicyManager
|
when(mDevicePolicyManager
|
||||||
.createShowAdminSupportIntent(TEST_USER_ID, true))
|
.createShowAdminSupportIntent(TEST_USER_ID, true))
|
||||||
.thenReturn(ADMIN_SUPPORT_INTENT);
|
.thenReturn(ADMIN_SUPPORT_INTENT);
|
||||||
|
when(mService.getPackageManagerInternalLocked()).thenReturn(mPackageManagerInternal);
|
||||||
|
|
||||||
// Mock UserManager
|
// Mock UserManager
|
||||||
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
|
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
|
||||||
@@ -115,15 +122,18 @@ public class ActivityStartInterceptorTest {
|
|||||||
thenReturn(CONFIRM_CREDENTIALS_INTENT);
|
thenReturn(CONFIRM_CREDENTIALS_INTENT);
|
||||||
|
|
||||||
// Initialise activity info
|
// Initialise activity info
|
||||||
mAInfo.packageName = TEST_PACKAGE_NAME;
|
|
||||||
mAInfo.applicationInfo = new ApplicationInfo();
|
mAInfo.applicationInfo = new ApplicationInfo();
|
||||||
|
mAInfo.packageName = mAInfo.applicationInfo.packageName = TEST_PACKAGE_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuspendedPackage() {
|
public void testSuspendedByAdminPackage() {
|
||||||
// GIVEN the package we're about to launch is currently suspended
|
// GIVEN the package we're about to launch is currently suspended
|
||||||
mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
|
mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
|
||||||
|
|
||||||
|
when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
|
||||||
|
.thenReturn(PLATFORM_PACKAGE_NAME);
|
||||||
|
|
||||||
// THEN calling intercept returns true
|
// THEN calling intercept returns true
|
||||||
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
|
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
|
||||||
|
|
||||||
|
|||||||
@@ -199,13 +199,13 @@ public class PackageManagerSettingsTests {
|
|||||||
PACKAGE_NAME_1, 1L, 0.01, true, "appString1");
|
PACKAGE_NAME_1, 1L, 0.01, true, "appString1");
|
||||||
final PersistableBundle launcherExtras1 = getPersistableBundle(
|
final PersistableBundle launcherExtras1 = getPersistableBundle(
|
||||||
PACKAGE_NAME_1, 10L, 0.1, false, "launcherString1");
|
PACKAGE_NAME_1, 10L, 0.1, false, "launcherString1");
|
||||||
ps1.setSuspended(true, "suspendingPackage1", appExtras1, launcherExtras1, 0);
|
ps1.setSuspended(true, "suspendingPackage1", "dialogMsg1", appExtras1, launcherExtras1, 0);
|
||||||
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
|
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
|
||||||
|
|
||||||
ps2.setSuspended(true, "suspendingPackage2", null, null, 0);
|
ps2.setSuspended(true, "suspendingPackage2", "dialogMsg2", null, null, 0);
|
||||||
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
|
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
|
||||||
|
|
||||||
ps3.setSuspended(false, "irrelevant", null, null, 0);
|
ps3.setSuspended(false, "irrelevant", "irrevelant2", null, null, 0);
|
||||||
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
|
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
|
||||||
|
|
||||||
settingsUnderTest.writePackageRestrictionsLPr(0);
|
settingsUnderTest.writePackageRestrictionsLPr(0);
|
||||||
@@ -220,6 +220,7 @@ public class PackageManagerSettingsTests {
|
|||||||
readUserState(0);
|
readUserState(0);
|
||||||
assertThat(readPus1.suspended, is(true));
|
assertThat(readPus1.suspended, is(true));
|
||||||
assertThat(readPus1.suspendingPackage, equalTo("suspendingPackage1"));
|
assertThat(readPus1.suspendingPackage, equalTo("suspendingPackage1"));
|
||||||
|
assertThat(readPus1.dialogMessage, equalTo("dialogMsg1"));
|
||||||
assertThat(BaseBundle.kindofEquals(readPus1.suspendedAppExtras, appExtras1), is(true));
|
assertThat(BaseBundle.kindofEquals(readPus1.suspendedAppExtras, appExtras1), is(true));
|
||||||
assertThat(BaseBundle.kindofEquals(readPus1.suspendedLauncherExtras, launcherExtras1),
|
assertThat(BaseBundle.kindofEquals(readPus1.suspendedLauncherExtras, launcherExtras1),
|
||||||
is(true));
|
is(true));
|
||||||
@@ -228,12 +229,17 @@ public class PackageManagerSettingsTests {
|
|||||||
readUserState(0);
|
readUserState(0);
|
||||||
assertThat(readPus2.suspended, is(true));
|
assertThat(readPus2.suspended, is(true));
|
||||||
assertThat(readPus2.suspendingPackage, equalTo("suspendingPackage2"));
|
assertThat(readPus2.suspendingPackage, equalTo("suspendingPackage2"));
|
||||||
|
assertThat(readPus2.dialogMessage, equalTo("dialogMsg2"));
|
||||||
assertThat(readPus2.suspendedAppExtras, is(nullValue()));
|
assertThat(readPus2.suspendedAppExtras, is(nullValue()));
|
||||||
assertThat(readPus2.suspendedLauncherExtras, is(nullValue()));
|
assertThat(readPus2.suspendedLauncherExtras, is(nullValue()));
|
||||||
|
|
||||||
final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3).
|
final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3).
|
||||||
readUserState(0);
|
readUserState(0);
|
||||||
assertThat(readPus3.suspended, is(false));
|
assertThat(readPus3.suspended, is(false));
|
||||||
|
assertThat(readPus3.suspendingPackage, is(nullValue()));
|
||||||
|
assertThat(readPus3.dialogMessage, is(nullValue()));
|
||||||
|
assertThat(readPus3.suspendedAppExtras, is(nullValue()));
|
||||||
|
assertThat(readPus3.suspendedLauncherExtras, is(nullValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -184,30 +184,40 @@ public class PackageUserStateTest {
|
|||||||
launcherExtras2.putString("name", "launcherExtras2");
|
launcherExtras2.putString("name", "launcherExtras2");
|
||||||
final String suspendingPackage1 = "package1";
|
final String suspendingPackage1 = "package1";
|
||||||
final String suspendingPackage2 = "package2";
|
final String suspendingPackage2 = "package2";
|
||||||
|
final String dialogMessage1 = "dialogMessage1";
|
||||||
|
final String dialogMessage2 = "dialogMessage2";
|
||||||
|
|
||||||
final PackageUserState testUserState1 = new PackageUserState();
|
final PackageUserState testUserState1 = new PackageUserState();
|
||||||
testUserState1.suspended = true;
|
testUserState1.suspended = true;
|
||||||
testUserState1.suspendedAppExtras = appExtras1;
|
testUserState1.suspendedAppExtras = appExtras1;
|
||||||
testUserState1.suspendedLauncherExtras = launcherExtras1;
|
testUserState1.suspendedLauncherExtras = launcherExtras1;
|
||||||
testUserState1.suspendingPackage = suspendingPackage1;
|
testUserState1.suspendingPackage = suspendingPackage1;
|
||||||
|
testUserState1.dialogMessage = dialogMessage1;
|
||||||
|
|
||||||
final PackageUserState testUserState2 = new PackageUserState(testUserState1);
|
PackageUserState testUserState2 = new PackageUserState(testUserState1);
|
||||||
assertThat(testUserState1.equals(testUserState2), is(true));
|
assertThat(testUserState1.equals(testUserState2), is(true));
|
||||||
testUserState2.suspendingPackage = suspendingPackage2;
|
testUserState2.suspendingPackage = suspendingPackage2;
|
||||||
assertThat(testUserState1.equals(testUserState2), is(false));
|
assertThat(testUserState1.equals(testUserState2), is(false));
|
||||||
|
|
||||||
testUserState2.suspendingPackage = testUserState1.suspendingPackage;
|
testUserState2 = new PackageUserState(testUserState1);
|
||||||
testUserState2.suspendedAppExtras = appExtras2;
|
testUserState2.suspendedAppExtras = appExtras2;
|
||||||
assertThat(testUserState1.equals(testUserState2), is(false));
|
assertThat(testUserState1.equals(testUserState2), is(false));
|
||||||
|
|
||||||
testUserState2.suspendedAppExtras = testUserState1.suspendedAppExtras;
|
testUserState2 = new PackageUserState(testUserState1);
|
||||||
testUserState2.suspendedLauncherExtras = launcherExtras2;
|
testUserState2.suspendedLauncherExtras = launcherExtras2;
|
||||||
assertThat(testUserState1.equals(testUserState2), is(false));
|
assertThat(testUserState1.equals(testUserState2), is(false));
|
||||||
|
|
||||||
// Everything is different but irrelevant if suspended is false
|
testUserState2 = new PackageUserState(testUserState1);
|
||||||
|
testUserState2.dialogMessage = dialogMessage2;
|
||||||
|
assertThat(testUserState1.equals(testUserState2), is(false));
|
||||||
|
|
||||||
|
testUserState2 = new PackageUserState(testUserState1);
|
||||||
testUserState2.suspended = testUserState1.suspended = false;
|
testUserState2.suspended = testUserState1.suspended = false;
|
||||||
testUserState2.suspendedAppExtras = appExtras2;
|
// Everything is different but irrelevant if suspended is false
|
||||||
testUserState2.suspendingPackage = suspendingPackage2;
|
testUserState2.suspendingPackage = suspendingPackage2;
|
||||||
|
testUserState2.dialogMessage = dialogMessage2;
|
||||||
|
testUserState2.suspendedAppExtras = appExtras2;
|
||||||
|
testUserState2.suspendedLauncherExtras = launcherExtras2;
|
||||||
assertThat(testUserState1.equals(testUserState2), is(true));
|
assertThat(testUserState1.equals(testUserState2), is(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
|
|||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import android.app.AppGlobals;
|
import android.app.AppGlobals;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
@@ -41,8 +42,15 @@ import android.os.UserHandle;
|
|||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.filters.LargeTest;
|
import android.support.test.filters.LargeTest;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.support.test.uiautomator.By;
|
||||||
|
import android.support.test.uiautomator.UiDevice;
|
||||||
|
import android.support.test.uiautomator.UiObject2;
|
||||||
|
import android.support.test.uiautomator.Until;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.IWindowManager;
|
||||||
|
import android.view.WindowManagerGlobal;
|
||||||
|
|
||||||
|
import com.android.servicestests.apps.suspendtestapp.SuspendTestActivity;
|
||||||
import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
|
import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@@ -68,14 +76,25 @@ public class SuspendPackagesTest {
|
|||||||
INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_SUSPENDED";
|
INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_SUSPENDED";
|
||||||
public static final String ACTION_REPORT_MY_PACKAGE_UNSUSPENDED =
|
public static final String ACTION_REPORT_MY_PACKAGE_UNSUSPENDED =
|
||||||
INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_UNSUSPENDED";
|
INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_UNSUSPENDED";
|
||||||
|
public static final String ACTION_REPORT_TEST_ACTIVITY_STARTED =
|
||||||
|
INSTRUMENTATION_PACKAGE + ".action.REPORT_TEST_ACTIVITY_STARTED";
|
||||||
|
public static final String ACTION_REPORT_TEST_ACTIVITY_STOPPED =
|
||||||
|
INSTRUMENTATION_PACKAGE + ".action.REPORT_TEST_ACTIVITY_STOPPED";
|
||||||
|
public static final String ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED =
|
||||||
|
INSTRUMENTATION_PACKAGE + ".action.REPORT_MORE_DETAILS_ACTIVITY_STARTED";
|
||||||
|
public static final String ACTION_FINISH_TEST_ACTIVITY =
|
||||||
|
INSTRUMENTATION_PACKAGE + ".action.FINISH_TEST_ACTIVITY";
|
||||||
|
public static final String EXTRA_RECEIVED_PACKAGE_NAME =
|
||||||
|
SuspendPackagesTest.INSTRUMENTATION_PACKAGE + ".extra.RECEIVED_PACKAGE_NAME";
|
||||||
|
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
private LauncherApps mLauncherApps;
|
private LauncherApps mLauncherApps;
|
||||||
private Handler mReceiverHandler;
|
private Handler mReceiverHandler;
|
||||||
private ComponentName mTestReceiverComponent;
|
|
||||||
private AppCommunicationReceiver mAppCommsReceiver;
|
private AppCommunicationReceiver mAppCommsReceiver;
|
||||||
private StubbedCallback mTestCallback;
|
private StubbedCallback mTestCallback;
|
||||||
|
private UiDevice mUiDevice;
|
||||||
|
|
||||||
private static final class AppCommunicationReceiver extends BroadcastReceiver {
|
private static final class AppCommunicationReceiver extends BroadcastReceiver {
|
||||||
private Context context;
|
private Context context;
|
||||||
@@ -86,11 +105,12 @@ public class SuspendPackagesTest {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
void register(Handler handler) {
|
void register(Handler handler, String... actions) {
|
||||||
registered = true;
|
registered = true;
|
||||||
final IntentFilter intentFilter = new IntentFilter();
|
final IntentFilter intentFilter = new IntentFilter();
|
||||||
intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_SUSPENDED);
|
for (String action : actions) {
|
||||||
intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
|
intentFilter.addAction(action);
|
||||||
|
}
|
||||||
context.registerReceiver(this, intentFilter, null, handler);
|
context.registerReceiver(this, intentFilter, null, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,19 +130,28 @@ public class SuspendPackagesTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent receiveIntentFromApp() {
|
Intent pollForIntent(long secondsToWait) {
|
||||||
if (!registered) {
|
if (!registered) {
|
||||||
throw new IllegalStateException("Receiver not registered");
|
throw new IllegalStateException("Receiver not registered");
|
||||||
}
|
}
|
||||||
final Intent intent;
|
final Intent intent;
|
||||||
try {
|
try {
|
||||||
intent = intentQueue.poll(5, TimeUnit.SECONDS);
|
intent = intentQueue.poll(secondsToWait, TimeUnit.SECONDS);
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
throw new RuntimeException("Interrupted while waiting for app broadcast", ie);
|
throw new RuntimeException("Interrupted while waiting for app broadcast", ie);
|
||||||
}
|
}
|
||||||
assertNotNull("No intent received from app within 5 seconds", intent);
|
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void drainPendingBroadcasts() {
|
||||||
|
while (pollForIntent(5) != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent receiveIntentFromApp() {
|
||||||
|
final Intent intentReceived = pollForIntent(5);
|
||||||
|
assertNotNull("No intent received from app within 5 seconds", intentReceived);
|
||||||
|
return intentReceived;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -131,8 +160,7 @@ public class SuspendPackagesTest {
|
|||||||
mPackageManager = mContext.getPackageManager();
|
mPackageManager = mContext.getPackageManager();
|
||||||
mLauncherApps = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
|
mLauncherApps = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
|
||||||
mReceiverHandler = new Handler(Looper.getMainLooper());
|
mReceiverHandler = new Handler(Looper.getMainLooper());
|
||||||
mTestReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
|
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||||
SuspendTestReceiver.class.getCanonicalName());
|
|
||||||
IPackageManager ipm = AppGlobals.getPackageManager();
|
IPackageManager ipm = AppGlobals.getPackageManager();
|
||||||
try {
|
try {
|
||||||
// Otherwise implicit broadcasts will not be delivered.
|
// Otherwise implicit broadcasts will not be delivered.
|
||||||
@@ -151,9 +179,10 @@ public class SuspendPackagesTest {
|
|||||||
private Bundle requestAppAction(String action) throws InterruptedException {
|
private Bundle requestAppAction(String action) throws InterruptedException {
|
||||||
final AtomicReference<Bundle> result = new AtomicReference<>();
|
final AtomicReference<Bundle> result = new AtomicReference<>();
|
||||||
final CountDownLatch receiverLatch = new CountDownLatch(1);
|
final CountDownLatch receiverLatch = new CountDownLatch(1);
|
||||||
|
final ComponentName testReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
|
||||||
|
SuspendTestReceiver.class.getCanonicalName());
|
||||||
final Intent broadcastIntent = new Intent(action)
|
final Intent broadcastIntent = new Intent(action)
|
||||||
.setComponent(mTestReceiverComponent)
|
.setComponent(testReceiverComponent)
|
||||||
.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||||
mContext.sendOrderedBroadcast(broadcastIntent, null, new BroadcastReceiver() {
|
mContext.sendOrderedBroadcast(broadcastIntent, null, new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
@@ -175,9 +204,10 @@ public class SuspendPackagesTest {
|
|||||||
return extras;
|
return extras;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void suspendTestPackage(PersistableBundle appExtras, PersistableBundle launcherExtras) {
|
private void suspendTestPackage(PersistableBundle appExtras, PersistableBundle launcherExtras,
|
||||||
|
String dialogMessage) {
|
||||||
final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
|
final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
|
||||||
PACKAGES_TO_SUSPEND, true, appExtras, launcherExtras, null);
|
PACKAGES_TO_SUSPEND, true, appExtras, launcherExtras, dialogMessage);
|
||||||
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
|
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,6 +217,13 @@ public class SuspendPackagesTest {
|
|||||||
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
|
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startTestAppActivity() {
|
||||||
|
final Intent testActivity = new Intent()
|
||||||
|
.setComponent(new ComponentName(TEST_APP_PACKAGE_NAME,
|
||||||
|
SuspendTestActivity.class.getCanonicalName()))
|
||||||
|
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
mContext.startActivity(testActivity);
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean areSameExtras(BaseBundle expected, BaseBundle received) {
|
private static boolean areSameExtras(BaseBundle expected, BaseBundle received) {
|
||||||
if (expected != null) {
|
if (expected != null) {
|
||||||
@@ -199,13 +236,14 @@ public class SuspendPackagesTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void assertSameExtras(String message, BaseBundle expected, BaseBundle received) {
|
private static void assertSameExtras(String message, BaseBundle expected, BaseBundle received) {
|
||||||
assertTrue(message + ": [expected: " + expected + "; received: " + received + "]",
|
if (!areSameExtras(expected, received)) {
|
||||||
areSameExtras(expected, received));
|
fail(message + ": [expected: " + expected + "; received: " + received + "]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsPackageSuspended() {
|
public void testIsPackageSuspended() {
|
||||||
suspendTestPackage(null, null);
|
suspendTestPackage(null, null, null);
|
||||||
assertTrue("isPackageSuspended is false",
|
assertTrue("isPackageSuspended is false",
|
||||||
mPackageManager.isPackageSuspended(TEST_APP_PACKAGE_NAME));
|
mPackageManager.isPackageSuspended(TEST_APP_PACKAGE_NAME));
|
||||||
}
|
}
|
||||||
@@ -217,7 +255,7 @@ public class SuspendPackagesTest {
|
|||||||
assertNull(resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
|
assertNull(resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
|
||||||
|
|
||||||
final PersistableBundle appExtras = getExtras("testSuspendedStateFromApp", 20, "20", 0.2);
|
final PersistableBundle appExtras = getExtras("testSuspendedStateFromApp", 20, "20", 0.2);
|
||||||
suspendTestPackage(appExtras, null);
|
suspendTestPackage(appExtras, null, null);
|
||||||
|
|
||||||
resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
|
resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
|
||||||
assertTrue("resultFromApp:suspended is false",
|
assertTrue("resultFromApp:suspended is false",
|
||||||
@@ -230,37 +268,39 @@ public class SuspendPackagesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMyPackageSuspendedUnsuspended() {
|
public void testMyPackageSuspendedUnsuspended() {
|
||||||
mAppCommsReceiver.register(mReceiverHandler);
|
mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED,
|
||||||
|
ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
|
||||||
|
mAppCommsReceiver.drainPendingBroadcasts();
|
||||||
final PersistableBundle appExtras = getExtras("testMyPackageSuspendBroadcasts", 1, "1", .1);
|
final PersistableBundle appExtras = getExtras("testMyPackageSuspendBroadcasts", 1, "1", .1);
|
||||||
suspendTestPackage(appExtras, null);
|
suspendTestPackage(appExtras, null, null);
|
||||||
Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
|
Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
|
||||||
assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
|
assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
|
||||||
ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
|
ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
|
||||||
assertSameExtras("Received app extras different to the ones supplied", appExtras,
|
assertSameExtras("Received app extras different to the ones supplied", appExtras,
|
||||||
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
|
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
|
||||||
unsuspendTestPackage();
|
unsuspendTestPackage();
|
||||||
intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
|
intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
|
||||||
assertTrue("MY_PACKAGE_UNSUSPENDED delivery not reported",
|
assertEquals("MY_PACKAGE_UNSUSPENDED delivery not reported",
|
||||||
ACTION_REPORT_MY_PACKAGE_UNSUSPENDED.equals(intentFromApp.getAction()));
|
ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdatingAppExtras() {
|
public void testUpdatingAppExtras() {
|
||||||
mAppCommsReceiver.register(mReceiverHandler);
|
mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED);
|
||||||
final PersistableBundle extras1 = getExtras("testMyPackageSuspendedOnChangingExtras", 1,
|
final PersistableBundle extras1 = getExtras("testMyPackageSuspendedOnChangingExtras", 1,
|
||||||
"1", 0.1);
|
"1", 0.1);
|
||||||
suspendTestPackage(extras1, null);
|
suspendTestPackage(extras1, null, null);
|
||||||
Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
|
Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
|
||||||
assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
|
assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
|
||||||
ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
|
ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
|
||||||
assertSameExtras("Received app extras different to the ones supplied", extras1,
|
assertSameExtras("Received app extras different to the ones supplied", extras1,
|
||||||
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
|
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
|
||||||
final PersistableBundle extras2 = getExtras("testMyPackageSuspendedOnChangingExtras", 2,
|
final PersistableBundle extras2 = getExtras("testMyPackageSuspendedOnChangingExtras", 2,
|
||||||
"2", 0.2);
|
"2", 0.2);
|
||||||
mPackageManager.setSuspendedPackageAppExtras(TEST_APP_PACKAGE_NAME, extras2);
|
mPackageManager.setSuspendedPackageAppExtras(TEST_APP_PACKAGE_NAME, extras2);
|
||||||
intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
|
intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
|
||||||
assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
|
assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
|
||||||
ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
|
ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
|
||||||
assertSameExtras("Received app extras different to the updated extras", extras2,
|
assertSameExtras("Received app extras different to the updated extras", extras2,
|
||||||
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
|
intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
|
||||||
}
|
}
|
||||||
@@ -273,13 +313,27 @@ public class SuspendPackagesTest {
|
|||||||
assertEquals(mContext.getOpPackageName(), unchangedPkgs[0]);
|
assertEquals(mContext.getOpPackageName(), unchangedPkgs[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testActivityStoppedOnSuspend() {
|
||||||
|
mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_TEST_ACTIVITY_STARTED,
|
||||||
|
ACTION_REPORT_TEST_ACTIVITY_STOPPED);
|
||||||
|
startTestAppActivity();
|
||||||
|
Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
|
||||||
|
assertEquals("Test activity start not reported",
|
||||||
|
ACTION_REPORT_TEST_ACTIVITY_STARTED, intentFromApp.getAction());
|
||||||
|
suspendTestPackage(null, null, null);
|
||||||
|
intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
|
||||||
|
assertEquals("Test activity stop not reported on suspending the test app",
|
||||||
|
ACTION_REPORT_TEST_ACTIVITY_STOPPED, intentFromApp.getAction());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetLauncherExtrasNonNull() {
|
public void testGetLauncherExtrasNonNull() {
|
||||||
final Bundle extrasWhenUnsuspended = mLauncherApps.getSuspendedPackageLauncherExtras(
|
final Bundle extrasWhenUnsuspended = mLauncherApps.getSuspendedPackageLauncherExtras(
|
||||||
TEST_APP_PACKAGE_NAME, mContext.getUser());
|
TEST_APP_PACKAGE_NAME, mContext.getUser());
|
||||||
assertNull("Non null extras when package unsuspended:", extrasWhenUnsuspended);
|
assertNull("Non null extras when package unsuspended:", extrasWhenUnsuspended);
|
||||||
final PersistableBundle launcherExtras = getExtras("testGetLauncherExtras", 1, "1", 0.1);
|
final PersistableBundle launcherExtras = getExtras("testGetLauncherExtras", 1, "1", 0.1);
|
||||||
suspendTestPackage(null, launcherExtras);
|
suspendTestPackage(null, launcherExtras, null);
|
||||||
final Bundle receivedExtras = mLauncherApps.getSuspendedPackageLauncherExtras(
|
final Bundle receivedExtras = mLauncherApps.getSuspendedPackageLauncherExtras(
|
||||||
TEST_APP_PACKAGE_NAME, mContext.getUser());
|
TEST_APP_PACKAGE_NAME, mContext.getUser());
|
||||||
assertSameExtras("Received launcher extras different to the ones supplied", launcherExtras,
|
assertSameExtras("Received launcher extras different to the ones supplied", launcherExtras,
|
||||||
@@ -288,7 +342,7 @@ public class SuspendPackagesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetLauncherExtrasNull() {
|
public void testGetLauncherExtrasNull() {
|
||||||
suspendTestPackage(null, null);
|
suspendTestPackage(null, null, null);
|
||||||
final Bundle extrasWhenNoneGiven = mLauncherApps.getSuspendedPackageLauncherExtras(
|
final Bundle extrasWhenNoneGiven = mLauncherApps.getSuspendedPackageLauncherExtras(
|
||||||
TEST_APP_PACKAGE_NAME, mContext.getUser());
|
TEST_APP_PACKAGE_NAME, mContext.getUser());
|
||||||
assertNull("Non null extras when null extras provided:", extrasWhenNoneGiven);
|
assertNull("Non null extras when null extras provided:", extrasWhenNoneGiven);
|
||||||
@@ -339,7 +393,7 @@ public class SuspendPackagesTest {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
|
mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
|
||||||
suspendTestPackage(null, suppliedExtras);
|
suspendTestPackage(null, suppliedExtras, null);
|
||||||
assertFalse("Both callbacks were invoked", twoCallbackLatch.await(5, TimeUnit.SECONDS));
|
assertFalse("Both callbacks were invoked", twoCallbackLatch.await(5, TimeUnit.SECONDS));
|
||||||
twoCallbackLatch.countDown();
|
twoCallbackLatch.countDown();
|
||||||
assertTrue("No callback was invoked", twoCallbackLatch.await(2, TimeUnit.SECONDS));
|
assertTrue("No callback was invoked", twoCallbackLatch.await(2, TimeUnit.SECONDS));
|
||||||
@@ -373,19 +427,53 @@ public class SuspendPackagesTest {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
|
mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
|
||||||
suspendTestPackage(null, suppliedExtras);
|
suspendTestPackage(null, suppliedExtras, null);
|
||||||
assertTrue("Callback not invoked", oneCallbackLatch.await(5, TimeUnit.SECONDS));
|
assertTrue("Callback not invoked", oneCallbackLatch.await(5, TimeUnit.SECONDS));
|
||||||
final String result = overridingOneCallbackResult.get();
|
final String result = overridingOneCallbackResult.get();
|
||||||
assertTrue("Callback did not complete as expected: " + result, result.isEmpty());
|
assertTrue("Callback did not complete as expected: " + result, result.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void turnScreenOn() throws Exception {
|
||||||
|
if (!mUiDevice.isScreenOn()) {
|
||||||
|
mUiDevice.wakeUp();
|
||||||
|
}
|
||||||
|
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
|
||||||
|
wm.dismissKeyguard(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInterceptorActivity() throws Exception {
|
||||||
|
turnScreenOn();
|
||||||
|
mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED,
|
||||||
|
ACTION_REPORT_TEST_ACTIVITY_STARTED);
|
||||||
|
final String testMessage = "This is a test message";
|
||||||
|
suspendTestPackage(null, null, testMessage);
|
||||||
|
startTestAppActivity();
|
||||||
|
assertNull("No broadcast was expected from app", mAppCommsReceiver.pollForIntent(2));
|
||||||
|
assertNotNull("Given dialog message not shown",
|
||||||
|
mUiDevice.wait(Until.findObject(By.text(testMessage)), 5000));
|
||||||
|
final String buttonText = "More details";
|
||||||
|
final UiObject2 moreDetailsButton = mUiDevice.findObject(
|
||||||
|
By.clickable(true).text(buttonText));
|
||||||
|
assertNotNull("\"More Details\" button not shown", moreDetailsButton);
|
||||||
|
moreDetailsButton.click();
|
||||||
|
final Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
|
||||||
|
assertEquals("\"More Details\" activity start not reported",
|
||||||
|
ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED, intentFromApp.getAction());
|
||||||
|
final String receivedPackageName = intentFromApp.getStringExtra(
|
||||||
|
EXTRA_RECEIVED_PACKAGE_NAME);
|
||||||
|
assertEquals("Wrong package name received by \"More Details\" activity",
|
||||||
|
TEST_APP_PACKAGE_NAME, receivedPackageName);
|
||||||
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() {
|
||||||
mAppCommsReceiver.unregister();
|
mAppCommsReceiver.unregister();
|
||||||
if (mTestCallback != null) {
|
if (mTestCallback != null) {
|
||||||
mLauncherApps.unregisterCallback(mTestCallback);
|
mLauncherApps.unregisterCallback(mTestCallback);
|
||||||
}
|
}
|
||||||
Thread.sleep(250); // To prevent any race with the next registerReceiver
|
mContext.sendBroadcast(new Intent(ACTION_FINISH_TEST_ACTIVITY)
|
||||||
|
.setPackage(TEST_APP_PACKAGE_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static abstract class StubbedCallback extends LauncherApps.Callback {
|
private static abstract class StubbedCallback extends LauncherApps.Callback {
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.pm;
|
||||||
|
|
||||||
|
import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED;
|
||||||
|
import static com.android.server.pm.SuspendPackagesTest.EXTRA_RECEIVED_PACKAGE_NAME;
|
||||||
|
import static com.android.server.pm.SuspendPackagesTest.INSTRUMENTATION_PACKAGE;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class SuspendedDetailsActivity extends Activity {
|
||||||
|
private static final String TAG = SuspendedDetailsActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
Log.d(TAG, "onStart");
|
||||||
|
final String suspendedPackage = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
|
||||||
|
super.onStart();
|
||||||
|
final Intent reportStart = new Intent(ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED)
|
||||||
|
.putExtra(EXTRA_RECEIVED_PACKAGE_NAME, suspendedPackage)
|
||||||
|
.setPackage(INSTRUMENTATION_PACKAGE);
|
||||||
|
sendBroadcast(reportStart);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ LOCAL_MODULE_TAGS := tests
|
|||||||
|
|
||||||
LOCAL_COMPATIBILITY_SUITE := device-tests
|
LOCAL_COMPATIBILITY_SUITE := device-tests
|
||||||
|
|
||||||
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
|
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator
|
||||||
|
|
||||||
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||||
LOCAL_SRC_FILES += ../../src/com/android/server/pm/SuspendPackagesTest.java
|
LOCAL_SRC_FILES += ../../src/com/android/server/pm/SuspendPackagesTest.java
|
||||||
|
|||||||
@@ -16,9 +16,45 @@
|
|||||||
|
|
||||||
package com.android.servicestests.apps.suspendtestapp;
|
package com.android.servicestests.apps.suspendtestapp;
|
||||||
|
|
||||||
|
import static com.android.server.pm.SuspendPackagesTest.ACTION_FINISH_TEST_ACTIVITY;
|
||||||
|
import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_TEST_ACTIVITY_STARTED;
|
||||||
|
import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_TEST_ACTIVITY_STOPPED;
|
||||||
|
import static com.android.server.pm.SuspendPackagesTest.INSTRUMENTATION_PACKAGE;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
public class SuspendTestActivity extends Activity {
|
public class SuspendTestActivity extends Activity {
|
||||||
private static final String TAG = SuspendTestActivity.class.getSimpleName();
|
private static final String TAG = SuspendTestActivity.class.getSimpleName();
|
||||||
|
|
||||||
}
|
private BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
Log.d(TAG, "Finishing test activity from receiver");
|
||||||
|
SuspendTestActivity.this.finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
Log.d(TAG, "onStart");
|
||||||
|
final Intent reportStart = new Intent(ACTION_REPORT_TEST_ACTIVITY_STARTED)
|
||||||
|
.setPackage(INSTRUMENTATION_PACKAGE);
|
||||||
|
sendBroadcast(reportStart);
|
||||||
|
registerReceiver(mFinishReceiver, new IntentFilter(ACTION_FINISH_TEST_ACTIVITY));
|
||||||
|
super.onStart();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
Log.d(TAG, "onStop");
|
||||||
|
final Intent reportStop = new Intent(ACTION_REPORT_TEST_ACTIVITY_STOPPED)
|
||||||
|
.setPackage(INSTRUMENTATION_PACKAGE);
|
||||||
|
sendBroadcast(reportStop);
|
||||||
|
unregisterReceiver(mFinishReceiver);
|
||||||
|
super.onStop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user