Home | History | Annotate | Download | only in pm
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.pm;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertNotNull;
     22 import static org.junit.Assert.assertNull;
     23 import static org.junit.Assert.assertTrue;
     24 import static org.junit.Assert.fail;
     25 import static org.junit.Assume.assumeTrue;
     26 
     27 import android.app.AppGlobals;
     28 import android.content.BroadcastReceiver;
     29 import android.content.ComponentName;
     30 import android.content.Context;
     31 import android.content.Intent;
     32 import android.content.IntentFilter;
     33 import android.content.pm.IPackageManager;
     34 import android.content.pm.LauncherApps;
     35 import android.content.pm.PackageManager;
     36 import android.content.res.Resources;
     37 import android.os.BaseBundle;
     38 import android.os.Bundle;
     39 import android.os.Handler;
     40 import android.os.Looper;
     41 import android.os.PersistableBundle;
     42 import android.os.RemoteException;
     43 import android.os.UserHandle;
     44 import android.support.test.InstrumentationRegistry;
     45 import android.support.test.filters.LargeTest;
     46 import android.support.test.runner.AndroidJUnit4;
     47 import android.support.test.uiautomator.By;
     48 import android.support.test.uiautomator.UiDevice;
     49 import android.support.test.uiautomator.UiObject2;
     50 import android.support.test.uiautomator.Until;
     51 import android.util.Log;
     52 import android.view.IWindowManager;
     53 import android.view.WindowManagerGlobal;
     54 
     55 import com.android.servicestests.apps.suspendtestapp.SuspendTestActivity;
     56 import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
     57 
     58 import org.junit.After;
     59 import org.junit.Before;
     60 import org.junit.Test;
     61 import org.junit.runner.RunWith;
     62 
     63 import java.io.IOException;
     64 import java.util.Arrays;
     65 import java.util.concurrent.CountDownLatch;
     66 import java.util.concurrent.SynchronousQueue;
     67 import java.util.concurrent.TimeUnit;
     68 import java.util.concurrent.atomic.AtomicReference;
     69 
     70 @RunWith(AndroidJUnit4.class)
     71 @LargeTest
     72 public class SuspendPackagesTest {
     73     private static final String TAG = SuspendPackagesTest.class.getSimpleName();
     74     private static final String TEST_APP_LABEL = "Suspend Test App";
     75     private static final String TEST_APP_PACKAGE_NAME = SuspendTestReceiver.PACKAGE_NAME;
     76     private static final String[] PACKAGES_TO_SUSPEND = new String[]{TEST_APP_PACKAGE_NAME};
     77 
     78     public static final String INSTRUMENTATION_PACKAGE = "com.android.frameworks.servicestests";
     79     public static final String ACTION_REPORT_MY_PACKAGE_SUSPENDED =
     80             INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_SUSPENDED";
     81     public static final String ACTION_REPORT_MY_PACKAGE_UNSUSPENDED =
     82             INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_UNSUSPENDED";
     83     public static final String ACTION_REPORT_TEST_ACTIVITY_STARTED =
     84             INSTRUMENTATION_PACKAGE + ".action.REPORT_TEST_ACTIVITY_STARTED";
     85     public static final String ACTION_REPORT_TEST_ACTIVITY_STOPPED =
     86             INSTRUMENTATION_PACKAGE + ".action.REPORT_TEST_ACTIVITY_STOPPED";
     87     public static final String ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED =
     88             INSTRUMENTATION_PACKAGE + ".action.REPORT_MORE_DETAILS_ACTIVITY_STARTED";
     89     public static final String ACTION_FINISH_TEST_ACTIVITY =
     90             INSTRUMENTATION_PACKAGE + ".action.FINISH_TEST_ACTIVITY";
     91     public static final String EXTRA_RECEIVED_PACKAGE_NAME =
     92             SuspendPackagesTest.INSTRUMENTATION_PACKAGE + ".extra.RECEIVED_PACKAGE_NAME";
     93 
     94 
     95     private Context mContext;
     96     private PackageManager mPackageManager;
     97     private LauncherApps mLauncherApps;
     98     private Handler mReceiverHandler;
     99     private AppCommunicationReceiver mAppCommsReceiver;
    100     private StubbedCallback mTestCallback;
    101     private UiDevice mUiDevice;
    102     private ComponentName mDeviceAdminComponent;
    103     private boolean mPoSet;
    104     private boolean mDoSet;
    105 
    106     private static final class AppCommunicationReceiver extends BroadcastReceiver {
    107         private Context context;
    108         private boolean registered;
    109         private SynchronousQueue<Intent> intentQueue = new SynchronousQueue<>();
    110 
    111         AppCommunicationReceiver(Context context) {
    112             this.context = context;
    113         }
    114 
    115         void register(Handler handler, String... actions) {
    116             registered = true;
    117             final IntentFilter intentFilter = new IntentFilter();
    118             for (String action : actions) {
    119                 intentFilter.addAction(action);
    120             }
    121             context.registerReceiver(this, intentFilter, null, handler);
    122         }
    123 
    124         void unregister() {
    125             if (registered) {
    126                 context.unregisterReceiver(this);
    127             }
    128         }
    129 
    130         @Override
    131         public void onReceive(Context context, Intent intent) {
    132             Log.d(TAG, "AppCommunicationReceiver#onReceive: " + intent.getAction());
    133             try {
    134                 intentQueue.offer(intent, 5, TimeUnit.SECONDS);
    135             } catch (InterruptedException ie) {
    136                 throw new RuntimeException("Receiver thread interrupted", ie);
    137             }
    138         }
    139 
    140         Intent pollForIntent(long secondsToWait) {
    141             if (!registered) {
    142                 throw new IllegalStateException("Receiver not registered");
    143             }
    144             final Intent intent;
    145             try {
    146                 intent = intentQueue.poll(secondsToWait, TimeUnit.SECONDS);
    147             } catch (InterruptedException ie) {
    148                 throw new RuntimeException("Interrupted while waiting for app broadcast", ie);
    149             }
    150             return intent;
    151         }
    152 
    153         void drainPendingBroadcasts() {
    154             while (pollForIntent(5) != null);
    155         }
    156 
    157         Intent receiveIntentFromApp() {
    158             final Intent intentReceived = pollForIntent(5);
    159             assertNotNull("No intent received from app within 5 seconds", intentReceived);
    160             return intentReceived;
    161         }
    162     }
    163 
    164     @Before
    165     public void setUp() {
    166         mContext = InstrumentationRegistry.getTargetContext();
    167         mPackageManager = mContext.getPackageManager();
    168         mLauncherApps = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
    169         mReceiverHandler = new Handler(Looper.getMainLooper());
    170         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
    171         mDeviceAdminComponent = new ComponentName(mContext,
    172                 "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1");
    173         IPackageManager ipm = AppGlobals.getPackageManager();
    174         try {
    175             // Otherwise implicit broadcasts will not be delivered.
    176             ipm.setPackageStoppedState(TEST_APP_PACKAGE_NAME, false, mContext.getUserId());
    177         } catch (RemoteException e) {
    178             e.rethrowAsRuntimeException();
    179         }
    180         unsuspendTestPackage();
    181         mAppCommsReceiver = new AppCommunicationReceiver(mContext);
    182     }
    183 
    184     /**
    185      * Care should be taken when used with {@link #mAppCommsReceiver} in the same test as both use
    186      * the same handler.
    187      */
    188     private Bundle requestAppAction(String action) throws InterruptedException {
    189         final AtomicReference<Bundle> result = new AtomicReference<>();
    190         final CountDownLatch receiverLatch = new CountDownLatch(1);
    191         final ComponentName testReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
    192                 SuspendTestReceiver.class.getCanonicalName());
    193         final Intent broadcastIntent = new Intent(action)
    194                 .setComponent(testReceiverComponent)
    195                 .setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    196         mContext.sendOrderedBroadcast(broadcastIntent, null, new BroadcastReceiver() {
    197             @Override
    198             public void onReceive(Context context, Intent intent) {
    199                 result.set(getResultExtras(true));
    200                 receiverLatch.countDown();
    201             }
    202         }, mReceiverHandler, 0, null, null);
    203 
    204         assertTrue("Test receiver timed out ", receiverLatch.await(5, TimeUnit.SECONDS));
    205         return result.get();
    206     }
    207 
    208     private PersistableBundle getExtras(String keyPrefix, long lval, String sval, double dval) {
    209         final PersistableBundle extras = new PersistableBundle(3);
    210         extras.putLong(keyPrefix + ".LONG_VALUE", lval);
    211         extras.putDouble(keyPrefix + ".DOUBLE_VALUE", dval);
    212         extras.putString(keyPrefix + ".STRING_VALUE", sval);
    213         return extras;
    214     }
    215 
    216     private void suspendTestPackage(PersistableBundle appExtras, PersistableBundle launcherExtras,
    217             String dialogMessage) {
    218         final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
    219                 PACKAGES_TO_SUSPEND, true, appExtras, launcherExtras, dialogMessage);
    220         assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
    221     }
    222 
    223     private void unsuspendTestPackage() {
    224         final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
    225                 PACKAGES_TO_SUSPEND, false, null, null, null);
    226         assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
    227     }
    228 
    229     private void startTestAppActivity() {
    230         final Intent testActivity = new Intent()
    231                 .setComponent(new ComponentName(TEST_APP_PACKAGE_NAME,
    232                         SuspendTestActivity.class.getCanonicalName()))
    233                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    234         mContext.startActivity(testActivity);
    235     }
    236 
    237     private static boolean areSameExtras(BaseBundle expected, BaseBundle received) {
    238         if (expected != null) {
    239             expected.get(""); // hack to unparcel the bundles.
    240         }
    241         if (received != null) {
    242             received.get("");
    243         }
    244         return BaseBundle.kindofEquals(expected, received);
    245     }
    246 
    247     private static void assertSameExtras(String message, BaseBundle expected, BaseBundle received) {
    248         if (!areSameExtras(expected, received)) {
    249             fail(message + ": [expected: " + expected + "; received: " + received + "]");
    250         }
    251     }
    252 
    253     @Test
    254     public void testIsPackageSuspended() throws Exception {
    255         suspendTestPackage(null, null, null);
    256         assertTrue("isPackageSuspended is false",
    257                 mPackageManager.isPackageSuspended(TEST_APP_PACKAGE_NAME));
    258     }
    259 
    260     @Test
    261     public void testSuspendedStateFromApp() throws Exception {
    262         Bundle resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
    263         assertFalse(resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED, true));
    264         assertNull(resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
    265 
    266         final PersistableBundle appExtras = getExtras("testSuspendedStateFromApp", 20, "20", 0.2);
    267         suspendTestPackage(appExtras, null, null);
    268 
    269         resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
    270         assertTrue("resultFromApp:suspended is false",
    271                 resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED));
    272         final Bundle receivedAppExtras =
    273                 resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS);
    274         assertSameExtras("Received app extras different to the ones supplied",
    275                 appExtras, receivedAppExtras);
    276     }
    277 
    278     @Test
    279     public void testMyPackageSuspendedUnsuspended() {
    280         mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED,
    281                 ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
    282         mAppCommsReceiver.drainPendingBroadcasts();
    283         final PersistableBundle appExtras = getExtras("testMyPackageSuspendBroadcasts", 1, "1", .1);
    284         suspendTestPackage(appExtras, null, null);
    285         Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
    286         assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
    287                 ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
    288         assertSameExtras("Received app extras different to the ones supplied", appExtras,
    289                 intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
    290         unsuspendTestPackage();
    291         intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
    292         assertEquals("MY_PACKAGE_UNSUSPENDED delivery not reported",
    293                 ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
    294     }
    295 
    296     @Test
    297     public void testUpdatingAppExtras() {
    298         mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED);
    299         final PersistableBundle extras1 = getExtras("testMyPackageSuspendedOnChangingExtras", 1,
    300                 "1", 0.1);
    301         suspendTestPackage(extras1, null, null);
    302         Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
    303         assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
    304                 ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
    305         assertSameExtras("Received app extras different to the ones supplied", extras1,
    306                 intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
    307         final PersistableBundle extras2 = getExtras("testMyPackageSuspendedOnChangingExtras", 2,
    308                 "2", 0.2);
    309         suspendTestPackage(extras2, null, null);
    310         intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
    311         assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
    312                 ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
    313         assertSameExtras("Received app extras different to the updated extras", extras2,
    314                 intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
    315     }
    316 
    317     @Test
    318     public void testCannotSuspendSelf() {
    319         final String[] unchangedPkgs = mPackageManager.setPackagesSuspended(
    320                 new String[]{mContext.getOpPackageName()}, true, null, null, null);
    321         assertTrue(unchangedPkgs.length == 1);
    322         assertEquals(mContext.getOpPackageName(), unchangedPkgs[0]);
    323     }
    324 
    325     @Test
    326     public void testActivityStoppedOnSuspend() {
    327         mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_TEST_ACTIVITY_STARTED,
    328                 ACTION_REPORT_TEST_ACTIVITY_STOPPED);
    329         startTestAppActivity();
    330         Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
    331         assertEquals("Test activity start not reported",
    332                 ACTION_REPORT_TEST_ACTIVITY_STARTED, intentFromApp.getAction());
    333         suspendTestPackage(null, null, null);
    334         intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
    335         assertEquals("Test activity stop not reported on suspending the test app",
    336                 ACTION_REPORT_TEST_ACTIVITY_STOPPED, intentFromApp.getAction());
    337     }
    338 
    339     @Test
    340     public void testGetLauncherExtrasNonNull() {
    341         final Bundle extrasWhenUnsuspended = mLauncherApps.getSuspendedPackageLauncherExtras(
    342                 TEST_APP_PACKAGE_NAME, mContext.getUser());
    343         assertNull("Non null extras when package unsuspended:", extrasWhenUnsuspended);
    344         final PersistableBundle launcherExtras = getExtras("testGetLauncherExtras", 1, "1", 0.1);
    345         suspendTestPackage(null, launcherExtras, null);
    346         final Bundle receivedExtras = mLauncherApps.getSuspendedPackageLauncherExtras(
    347                 TEST_APP_PACKAGE_NAME, mContext.getUser());
    348         assertSameExtras("Received launcher extras different to the ones supplied", launcherExtras,
    349                 receivedExtras);
    350     }
    351 
    352     @Test
    353     public void testGetLauncherExtrasNull() {
    354         suspendTestPackage(null, null, null);
    355         final Bundle extrasWhenNoneGiven = mLauncherApps.getSuspendedPackageLauncherExtras(
    356                 TEST_APP_PACKAGE_NAME, mContext.getUser());
    357         assertNull("Non null extras when null extras provided:", extrasWhenNoneGiven);
    358     }
    359 
    360     @Test
    361     public void testGetLauncherExtrasInvalidPackage() {
    362         final Bundle extrasForInvalidPackage = mLauncherApps.getSuspendedPackageLauncherExtras(
    363                 "test.nonexistent.packagename", mContext.getUser());
    364         assertNull("Non null extras for an invalid package:", extrasForInvalidPackage);
    365     }
    366 
    367     @Test
    368     public void testOnPackagesSuspendedNewAndOld() throws InterruptedException {
    369         final PersistableBundle suppliedExtras = getExtras(
    370                 "testOnPackagesSuspendedNewAndOld", 2, "2", 0.2);
    371         final AtomicReference<String> overridingBothCallbackResult = new AtomicReference<>("");
    372         final CountDownLatch twoCallbackLatch = new CountDownLatch(2);
    373         mTestCallback = new StubbedCallback() {
    374             @Override
    375             public void onPackagesSuspended(String[] packageNames, UserHandle user) {
    376                 overridingBothCallbackResult.set(overridingBothCallbackResult.get()
    377                         + "Old callback called even when the new one is overriden. ");
    378                 twoCallbackLatch.countDown();
    379             }
    380 
    381             @Override
    382             public void onPackagesSuspended(String[] packageNames, UserHandle user,
    383                     Bundle launcherExtras) {
    384                 final StringBuilder errorString = new StringBuilder();
    385                 if (!Arrays.equals(packageNames, PACKAGES_TO_SUSPEND)) {
    386                     errorString.append("Received unexpected packageNames in onPackagesSuspended:");
    387                     for (String packageName : packageNames) {
    388                         errorString.append(" " + packageName);
    389                     }
    390                     errorString.append(". ");
    391                 }
    392                 if (user.getIdentifier() != mContext.getUserId()) {
    393                     errorString.append("Received wrong user " + user.getIdentifier() + ". ");
    394                 }
    395                 if (!areSameExtras(launcherExtras, suppliedExtras)) {
    396                     errorString.append("Unexpected launcherExtras, supplied: " + suppliedExtras
    397                             + ", received: " + launcherExtras + ". ");
    398                 }
    399                 overridingBothCallbackResult.set(overridingBothCallbackResult.get()
    400                         + errorString.toString());
    401                 twoCallbackLatch.countDown();
    402             }
    403         };
    404         mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
    405         suspendTestPackage(null, suppliedExtras, null);
    406         assertFalse("Both callbacks were invoked", twoCallbackLatch.await(5, TimeUnit.SECONDS));
    407         twoCallbackLatch.countDown();
    408         assertTrue("No callback was invoked", twoCallbackLatch.await(2, TimeUnit.SECONDS));
    409         final String result = overridingBothCallbackResult.get();
    410         assertTrue("Callbacks did not complete as expected: " + result, result.isEmpty());
    411     }
    412 
    413     @Test
    414     public void testOnPackagesSuspendedOld() throws InterruptedException {
    415         final PersistableBundle suppliedExtras = getExtras(
    416                 "testOnPackagesSuspendedOld", 2, "2", 0.2);
    417         final AtomicReference<String> overridingOneCallbackResult = new AtomicReference<>("");
    418         final CountDownLatch oneCallbackLatch = new CountDownLatch(1);
    419         mTestCallback = new StubbedCallback() {
    420             @Override
    421             public void onPackagesSuspended(String[] packageNames, UserHandle user) {
    422                 final StringBuilder errorString = new StringBuilder();
    423                 if (!Arrays.equals(packageNames, PACKAGES_TO_SUSPEND)) {
    424                     errorString.append("Received unexpected packageNames in onPackagesSuspended:");
    425                     for (String packageName : packageNames) {
    426                         errorString.append(" " + packageName);
    427                     }
    428                     errorString.append(". ");
    429                 }
    430                 if (user.getIdentifier() != mContext.getUserId()) {
    431                     errorString.append("Received wrong user " + user.getIdentifier() + ". ");
    432                 }
    433                 overridingOneCallbackResult.set(overridingOneCallbackResult.get()
    434                         + errorString.toString());
    435                 oneCallbackLatch.countDown();
    436             }
    437         };
    438         mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
    439         suspendTestPackage(null, suppliedExtras, null);
    440         assertTrue("Callback not invoked", oneCallbackLatch.await(5, TimeUnit.SECONDS));
    441         final String result = overridingOneCallbackResult.get();
    442         assertTrue("Callback did not complete as expected: " + result, result.isEmpty());
    443     }
    444 
    445     private void turnScreenOn() throws Exception {
    446         if (!mUiDevice.isScreenOn()) {
    447             mUiDevice.wakeUp();
    448         }
    449         final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
    450         wm.dismissKeyguard(null, null);
    451     }
    452 
    453     @Test
    454     public void testInterceptorActivity() throws Exception {
    455         turnScreenOn();
    456         mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED,
    457                 ACTION_REPORT_TEST_ACTIVITY_STARTED);
    458         final String testMessage = "This is a test message to report suspension of %1$s";
    459         suspendTestPackage(null, null, testMessage);
    460         startTestAppActivity();
    461         assertNull("No broadcast was expected from app", mAppCommsReceiver.pollForIntent(2));
    462         assertNotNull("Given dialog message not shown", mUiDevice.wait(
    463                 Until.findObject(By.text(String.format(testMessage, TEST_APP_LABEL))), 5000));
    464         final String buttonText = mContext.getResources().getString(Resources.getSystem()
    465                 .getIdentifier("app_suspended_more_details", "string", "android"));
    466         final UiObject2 moreDetailsButton = mUiDevice.findObject(
    467                 By.clickable(true).text(buttonText));
    468         assertNotNull(buttonText + " button not shown", moreDetailsButton);
    469         moreDetailsButton.click();
    470         final Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
    471         assertEquals(buttonText + " activity start not reported",
    472                 ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED, intentFromApp.getAction());
    473         final String receivedPackageName = intentFromApp.getStringExtra(
    474                 EXTRA_RECEIVED_PACKAGE_NAME);
    475         assertEquals("Wrong package name received by " + buttonText + " activity",
    476                 TEST_APP_PACKAGE_NAME, receivedPackageName);
    477     }
    478 
    479     private boolean setProfileOwner() throws IOException {
    480         final String result = mUiDevice.executeShellCommand("dpm set-profile-owner --user cur "
    481                 + mDeviceAdminComponent.flattenToString());
    482         return mPoSet = result.trim().startsWith("Success");
    483     }
    484 
    485     private boolean setDeviceOwner() throws IOException {
    486         final String result = mUiDevice.executeShellCommand("dpm set-device-owner --user cur "
    487                 + mDeviceAdminComponent.flattenToString());
    488         return mDoSet = result.trim().startsWith("Success");
    489     }
    490 
    491     private void removeProfileOrDeviceOwner() throws IOException {
    492         if (mPoSet || mDoSet) {
    493             mUiDevice.executeShellCommand("dpm remove-active-admin --user cur "
    494                     + mDeviceAdminComponent.flattenToString());
    495             mPoSet = mDoSet = false;
    496         }
    497     }
    498 
    499     @Test
    500     public void testCannotSuspendWhenProfileOwner() throws IOException {
    501         assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
    502         assertTrue("Profile-owner could not be set", setProfileOwner());
    503         try {
    504             suspendTestPackage(null, null, null);
    505             fail("Suspend succeeded. Expected UnsupportedOperationException");
    506         } catch (UnsupportedOperationException uex) {
    507         }
    508     }
    509 
    510     @Test
    511     public void testCannotSuspendWhenDeviceOwner() throws IOException {
    512         assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
    513         assertTrue("Device-owner could not be set", setDeviceOwner());
    514         try {
    515             suspendTestPackage(null, null, null);
    516             fail("Suspend succeeded. Expected UnsupportedOperationException");
    517         } catch (UnsupportedOperationException uex) {
    518         }
    519     }
    520 
    521     @Test
    522     public void testPackageUnsuspendedOnAddingDeviceOwner() throws IOException {
    523         assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
    524         mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
    525                 ACTION_REPORT_MY_PACKAGE_SUSPENDED);
    526         mAppCommsReceiver.drainPendingBroadcasts();
    527         suspendTestPackage(null, null, null);
    528         Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
    529         assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
    530         assertTrue("Device-owner could not be set", setDeviceOwner());
    531         intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
    532         assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
    533     }
    534 
    535     @Test
    536     public void testPackageUnsuspendedOnAddingProfileOwner() throws IOException {
    537         assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
    538         mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
    539                 ACTION_REPORT_MY_PACKAGE_SUSPENDED);
    540         mAppCommsReceiver.drainPendingBroadcasts();
    541         suspendTestPackage(null, null, null);
    542         Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
    543         assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
    544         assertTrue("Profile-owner could not be set", setProfileOwner());
    545         intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
    546         assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
    547     }
    548 
    549     @After
    550     public void tearDown() throws IOException {
    551         mAppCommsReceiver.unregister();
    552         if (mTestCallback != null) {
    553             mLauncherApps.unregisterCallback(mTestCallback);
    554         }
    555         removeProfileOrDeviceOwner();
    556         mContext.sendBroadcast(new Intent(ACTION_FINISH_TEST_ACTIVITY)
    557                 .setPackage(TEST_APP_PACKAGE_NAME));
    558     }
    559 
    560     private static abstract class StubbedCallback extends LauncherApps.Callback {
    561 
    562         @Override
    563         public void onPackageRemoved(String packageName, UserHandle user) {
    564         }
    565 
    566         @Override
    567         public void onPackageAdded(String packageName, UserHandle user) {
    568         }
    569 
    570         @Override
    571         public void onPackageChanged(String packageName, UserHandle user) {
    572         }
    573 
    574         @Override
    575         public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) {
    576 
    577         }
    578 
    579         @Override
    580         public void onPackagesUnavailable(String[] packageNames, UserHandle user,
    581                 boolean replacing) {
    582         }
    583     }
    584 }
    585