1/*
2 * Copyright (C) 2017 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
17package com.android.settings.applications;
18
19import android.app.AlertDialog;
20import android.app.LoaderManager;
21import android.app.admin.DevicePolicyManager;
22import android.content.Context;
23import android.content.Intent;
24import android.content.pm.ApplicationInfo;
25import android.content.pm.PackageInfo;
26import android.content.pm.PackageManager;
27import android.content.res.Resources;
28import android.os.BatteryStats;
29import android.os.Bundle;
30import android.os.UserManager;
31import android.support.v7.preference.Preference;
32import android.support.v7.preference.PreferenceManager;
33import android.support.v7.preference.PreferenceScreen;
34import android.view.View;
35import android.widget.Button;
36
37import com.android.internal.os.BatterySipper;
38import com.android.internal.os.BatteryStatsHelper;
39import com.android.settings.R;
40import com.android.settings.SettingsActivity;
41import com.android.settings.SettingsRobolectricTestRunner;
42import com.android.settings.TestConfig;
43import com.android.settings.applications.instantapps.InstantAppButtonsController;
44import com.android.settings.fuelgauge.BatteryUtils;
45import com.android.settings.testutils.FakeFeatureFactory;
46import com.android.settingslib.Utils;
47import com.android.settingslib.applications.AppUtils;
48import com.android.settingslib.applications.ApplicationsState.AppEntry;
49import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
50import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
51
52import org.junit.Before;
53import org.junit.Test;
54import org.junit.runner.RunWith;
55import org.mockito.Answers;
56import org.mockito.Mock;
57import org.mockito.MockitoAnnotations;
58import org.robolectric.RuntimeEnvironment;
59import org.robolectric.annotation.Config;
60import org.robolectric.annotation.Implementation;
61import org.robolectric.annotation.Implements;
62import org.robolectric.util.ReflectionHelpers;
63
64import java.util.ArrayList;
65import java.util.HashSet;
66import java.util.List;
67
68import static com.google.common.truth.Truth.assertThat;
69import static org.mockito.Matchers.any;
70import static org.mockito.Matchers.anyDouble;
71import static org.mockito.Matchers.anyInt;
72import static org.mockito.Matchers.anyString;
73import static org.mockito.Mockito.doReturn;
74import static org.mockito.Mockito.mock;
75import static org.mockito.Mockito.never;
76import static org.mockito.Mockito.spy;
77import static org.mockito.Mockito.times;
78import static org.mockito.Mockito.verify;
79import static org.mockito.Mockito.when;
80
81
82@RunWith(SettingsRobolectricTestRunner.class)
83@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
84public final class InstalledAppDetailsTest {
85
86    private static final String PACKAGE_NAME = "test_package_name";
87    private static final int TARGET_UID = 111;
88    private static final int OTHER_UID = 222;
89    private static final double BATTERY_LEVEL = 60;
90    private static final String BATTERY_LEVEL_STRING = "60%";
91
92    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
93    private Context mContext;
94    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
95    private UserManager mUserManager;
96    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
97    private SettingsActivity mActivity;
98    @Mock
99    private DevicePolicyManager mDevicePolicyManager;
100    @Mock
101    private BatterySipper mBatterySipper;
102    @Mock
103    private BatterySipper mOtherBatterySipper;
104    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
105    private BatteryStatsHelper mBatteryStatsHelper;
106    @Mock
107    private BatteryStats.Uid mUid;
108    @Mock
109    private PackageManager mPackageManager;
110    @Mock
111    private BatteryUtils mBatteryUtils;
112    @Mock
113    private LoaderManager mLoaderManager;
114
115    private FakeFeatureFactory mFeatureFactory;
116    private InstalledAppDetails mAppDetail;
117    private Context mShadowContext;
118    private Preference mBatteryPreference;
119
120
121    @Before
122    public void setUp() {
123        MockitoAnnotations.initMocks(this);
124        FakeFeatureFactory.setupForTest(mContext);
125        mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
126        mShadowContext = RuntimeEnvironment.application;
127        mAppDetail = spy(new InstalledAppDetails());
128        mAppDetail.mBatteryUtils = mBatteryUtils;
129
130        mBatteryPreference = new Preference(mShadowContext);
131        mAppDetail.mBatteryPreference = mBatteryPreference;
132
133        mBatterySipper.drainType = BatterySipper.DrainType.IDLE;
134        mBatterySipper.uidObj = mUid;
135        doReturn(TARGET_UID).when(mBatterySipper).getUid();
136        doReturn(OTHER_UID).when(mOtherBatterySipper).getUid();
137        doReturn(mActivity).when(mAppDetail).getActivity();
138        doReturn(mShadowContext).when(mAppDetail).getContext();
139        doReturn(mPackageManager).when(mActivity).getPackageManager();
140
141        // Default to not considering any apps to be instant (individual tests can override this).
142        ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
143                (InstantAppDataProvider) (i -> false));
144    }
145
146    @Test
147    public void shouldShowUninstallForAll_installForOneOtherUserOnly_shouldReturnTrue() {
148        when(mDevicePolicyManager.packageHasActiveAdmins(anyString())).thenReturn(false);
149        when(mUserManager.getUsers().size()).thenReturn(2);
150        ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
151        ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
152        final ApplicationInfo info = new ApplicationInfo();
153        info.enabled = true;
154        final AppEntry appEntry = mock(AppEntry.class);
155        appEntry.info = info;
156        final PackageInfo packageInfo = mock(PackageInfo.class);
157        ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
158
159        assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isTrue();
160    }
161
162    @Test
163    public void shouldShowUninstallForAll_installForSelfOnly_shouldReturnFalse() {
164        when(mDevicePolicyManager.packageHasActiveAdmins(anyString())).thenReturn(false);
165        when(mUserManager.getUsers().size()).thenReturn(2);
166        ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
167        ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
168        final ApplicationInfo info = new ApplicationInfo();
169        info.flags = ApplicationInfo.FLAG_INSTALLED;
170        info.enabled = true;
171        final AppEntry appEntry = mock(AppEntry.class);
172        appEntry.info = info;
173        final PackageInfo packageInfo = mock(PackageInfo.class);
174        ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
175
176        assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isFalse();
177    }
178
179    @Test
180    public void getStorageSummary_shouldWorkForExternal() {
181        Context context = RuntimeEnvironment.application.getApplicationContext();
182        AppStorageStats stats = mock(AppStorageStats.class);
183        when(stats.getTotalBytes()).thenReturn(1L);
184
185        assertThat(InstalledAppDetails.getStorageSummary(context, stats, true))
186                .isEqualTo("1.00B used in external storage");
187    }
188
189    @Test
190    public void getStorageSummary_shouldWorkForInternal() {
191        Context context = RuntimeEnvironment.application.getApplicationContext();
192        AppStorageStats stats = mock(AppStorageStats.class);
193        when(stats.getTotalBytes()).thenReturn(1L);
194
195        assertThat(InstalledAppDetails.getStorageSummary(context, stats, false))
196                .isEqualTo("1.00B used in internal storage");
197    }
198
199    @Test
200    public void launchFragment_hasNoPackageInfo_shouldFinish() {
201        ReflectionHelpers.setField(mAppDetail, "mPackageInfo", null);
202
203        assertThat(mAppDetail.ensurePackageInfoAvailable(mActivity)).isFalse();
204        verify(mActivity).finishAndRemoveTask();
205    }
206
207    @Test
208    public void launchFragment_hasPackageInfo_shouldReturnTrue() {
209        final PackageInfo packageInfo = mock(PackageInfo.class);
210        ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
211
212        assertThat(mAppDetail.ensurePackageInfoAvailable(mActivity)).isTrue();
213        verify(mActivity, never()).finishAndRemoveTask();
214    }
215
216    @Test
217    public void packageSizeChange_isOtherPackage_shouldNotRefreshUi() {
218        ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
219        mAppDetail.onPackageSizeChanged("Not_" + PACKAGE_NAME);
220
221        verify(mAppDetail, never()).refreshUi();
222    }
223
224    @Test
225    public void packageSizeChange_isOwnPackage_shouldRefreshUi() {
226        doReturn(Boolean.TRUE).when(mAppDetail).refreshUi();
227        ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
228
229        mAppDetail.onPackageSizeChanged(PACKAGE_NAME);
230
231        verify(mAppDetail).refreshUi();
232    }
233
234    @Test
235    public void launchPowerUsageDetailFragment_shouldNotCrash() {
236        mAppDetail.mBatteryPreference = mBatteryPreference;
237        mAppDetail.mSipper = mBatterySipper;
238        mAppDetail.mBatteryHelper = mBatteryStatsHelper;
239
240        // Should not crash
241        mAppDetail.onPreferenceClick(mBatteryPreference);
242    }
243
244    // Tests that we don't show the "uninstall for all users" button for instant apps.
245    @Test
246    public void instantApps_noUninstallForAllButton() {
247        // Make this app appear to be instant.
248        ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
249                (InstantAppDataProvider) (i -> true));
250        when(mDevicePolicyManager.packageHasActiveAdmins(anyString())).thenReturn(false);
251        when(mUserManager.getUsers().size()).thenReturn(2);
252
253        final ApplicationInfo info = new ApplicationInfo();
254        info.enabled = true;
255        final AppEntry appEntry = mock(AppEntry.class);
256        appEntry.info = info;
257        final PackageInfo packageInfo = mock(PackageInfo.class);
258
259        ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
260        ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
261        ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
262
263        assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isFalse();
264    }
265
266    // Tests that we don't show the uninstall button for instant apps"
267    @Test
268    public void instantApps_noUninstallButton() {
269        // Make this app appear to be instant.
270        ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
271                (InstantAppDataProvider) (i -> true));
272        final ApplicationInfo info = new ApplicationInfo();
273        info.flags = ApplicationInfo.FLAG_INSTALLED;
274        info.enabled = true;
275        final AppEntry appEntry = mock(AppEntry.class);
276        appEntry.info = info;
277        final PackageInfo packageInfo = mock(PackageInfo.class);
278        packageInfo.applicationInfo = info;
279        final Button uninstallButton = mock(Button.class);
280
281        ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
282        ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
283        ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
284        ReflectionHelpers.setField(mAppDetail, "mUninstallButton", uninstallButton);
285
286        mAppDetail.initUnintsallButtonForUserApp();
287        verify(uninstallButton).setVisibility(View.GONE);
288    }
289
290    // Tests that we don't show the force stop button for instant apps (they aren't allowed to run
291    // when they aren't in the foreground).
292    @Test
293    public void instantApps_noForceStop() {
294        // Make this app appear to be instant.
295        ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
296                (InstantAppDataProvider) (i -> true));
297        final PackageInfo packageInfo = mock(PackageInfo.class);
298        final AppEntry appEntry = mock(AppEntry.class);
299        final ApplicationInfo info = new ApplicationInfo();
300        appEntry.info = info;
301        final Button forceStopButton = mock(Button.class);
302
303        ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
304        ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
305        ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
306        ReflectionHelpers.setField(mAppDetail, "mForceStopButton", forceStopButton);
307
308        mAppDetail.checkForceStop();
309        verify(forceStopButton).setVisibility(View.GONE);
310    }
311
312    @Test
313    public void instantApps_buttonControllerHandlesDialog() {
314        InstantAppButtonsController mockController = mock(InstantAppButtonsController.class);
315        ReflectionHelpers.setField(
316                mAppDetail, "mInstantAppButtonsController", mockController);
317        // Make sure first that button controller is not called for supported dialog id
318        AlertDialog mockDialog = mock(AlertDialog.class);
319        when(mockController.createDialog(InstantAppButtonsController.DLG_CLEAR_APP))
320                .thenReturn(mockDialog);
321        assertThat(mAppDetail.createDialog(InstantAppButtonsController.DLG_CLEAR_APP, 0))
322                .isEqualTo(mockDialog);
323        verify(mockController).createDialog(InstantAppButtonsController.DLG_CLEAR_APP);
324    }
325
326    // A helper class for testing the InstantAppButtonsController - it lets us look up the
327    // preference associated with a key for instant app buttons and get back a mock
328    // LayoutPreference (to avoid a null pointer exception).
329    public static class InstalledAppDetailsWithMockInstantButtons extends InstalledAppDetails {
330        @Mock
331        private LayoutPreference mInstantButtons;
332
333        public InstalledAppDetailsWithMockInstantButtons() {
334            super();
335            MockitoAnnotations.initMocks(this);
336        }
337
338        @Override
339        public Preference findPreference(CharSequence key) {
340            if (key == "instant_app_buttons") {
341                return mInstantButtons;
342            }
343            return super.findPreference(key);
344        }
345    }
346
347    @Test
348    public void instantApps_instantSpecificButtons() {
349        // Make this app appear to be instant.
350        ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
351                (InstantAppDataProvider) (i -> true));
352        final PackageInfo packageInfo = mock(PackageInfo.class);
353
354        final InstalledAppDetailsWithMockInstantButtons
355                fragment = new InstalledAppDetailsWithMockInstantButtons();
356        ReflectionHelpers.setField(fragment, "mPackageInfo", packageInfo);
357        ReflectionHelpers.setField(fragment, "mApplicationFeatureProvider",
358                mFeatureFactory.applicationFeatureProvider);
359
360        final InstantAppButtonsController buttonsController =
361                mock(InstantAppButtonsController.class);
362        when(buttonsController.setPackageName(anyString())).thenReturn(buttonsController);
363
364        when(mFeatureFactory.applicationFeatureProvider.newInstantAppButtonsController(
365                any(), any(), any())).thenReturn(buttonsController);
366
367        fragment.maybeAddInstantAppButtons();
368        verify(buttonsController).setPackageName(anyString());
369        verify(buttonsController).show();
370    }
371
372    @Test
373    public void instantApps_removeCorrectPref() {
374        PreferenceScreen mockPreferenceScreen = mock(PreferenceScreen.class);
375        PreferenceManager mockPreferenceManager = mock(PreferenceManager.class);
376        AppDomainsPreference mockAppDomainsPref = mock(AppDomainsPreference.class);
377        Preference mockLaunchPreference = mock(Preference.class);
378        PackageInfo mockPackageInfo = mock(PackageInfo.class);
379        PackageManager mockPackageManager = mock(PackageManager.class);
380        ReflectionHelpers.setField(
381                mAppDetail, "mLaunchPreference", mockLaunchPreference);
382        ReflectionHelpers.setField(
383                mAppDetail, "mInstantAppDomainsPreference", mockAppDomainsPref);
384        ReflectionHelpers.setField(
385                mAppDetail, "mPreferenceManager", mockPreferenceManager);
386        ReflectionHelpers.setField(
387                mAppDetail, "mPackageInfo", mockPackageInfo);
388        ReflectionHelpers.setField(
389                mAppDetail, "mPm", mockPackageManager);
390        when(mockPreferenceManager.getPreferenceScreen()).thenReturn(mockPreferenceScreen);
391
392        ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
393                (InstantAppDataProvider) (i -> false));
394        mAppDetail.prepareInstantAppPrefs();
395
396        // For the non instant case we remove the app domain pref, and leave the launch pref
397        verify(mockPreferenceScreen).removePreference(mockAppDomainsPref);
398        verify(mockPreferenceScreen, never()).removePreference(mockLaunchPreference);
399
400        // For the instant app case we remove the launch preff, and leave the app domain pref
401        ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
402                (InstantAppDataProvider) (i -> true));
403
404        mAppDetail.prepareInstantAppPrefs();
405        verify(mockPreferenceScreen).removePreference(mockLaunchPreference);
406        // Will be 1 still due to above call
407        verify(mockPreferenceScreen, times(1))
408                .removePreference(mockAppDomainsPref);
409    }
410
411    @Test
412    public void onActivityResult_uninstalledUpdates_shouldInvalidateOptionsMenu() {
413        doReturn(true).when(mAppDetail).refreshUi();
414
415        mAppDetail.onActivityResult(InstalledAppDetails.REQUEST_UNINSTALL, 0, mock(Intent.class));
416
417        verify(mActivity).invalidateOptionsMenu();
418    }
419
420    @Test
421    public void findTargetSipper_findCorrectSipper() {
422        List<BatterySipper> usageList = new ArrayList<>();
423        usageList.add(mBatterySipper);
424        usageList.add(mOtherBatterySipper);
425        doReturn(usageList).when(mBatteryStatsHelper).getUsageList();
426
427        assertThat(mAppDetail.findTargetSipper(mBatteryStatsHelper, TARGET_UID)).isEqualTo(
428                mBatterySipper);
429    }
430
431    @Test
432    public void updateBattery_noBatteryStats_summaryNo() {
433        doReturn(mShadowContext.getString(R.string.no_battery_summary)).when(mAppDetail).getString(
434                R.string.no_battery_summary);
435        mAppDetail.updateBattery();
436
437        assertThat(mBatteryPreference.getSummary()).isEqualTo(
438                "No battery use since last full charge");
439    }
440
441    @Test
442    public void updateBattery_hasBatteryStats_summaryPercent() {
443        mAppDetail.mBatteryHelper = mBatteryStatsHelper;
444        mAppDetail.mSipper = mBatterySipper;
445        doReturn(BATTERY_LEVEL).when(mBatteryUtils).calculateBatteryPercent(anyDouble(),
446                anyDouble(), anyDouble(), anyInt());
447        doReturn(mShadowContext.getString(R.string.battery_summary, BATTERY_LEVEL_STRING)).when(
448                mAppDetail).getString(R.string.battery_summary, BATTERY_LEVEL_STRING);
449        doReturn(new ArrayList<>()).when(mBatteryStatsHelper).getUsageList();
450
451        mAppDetail.updateBattery();
452
453        assertThat(mBatteryPreference.getSummary()).isEqualTo("60% use since last full charge");
454    }
455
456    @Test
457    public void isBatteryStatsAvailable_hasBatteryStatsHelperAndSipper_returnTrue() {
458        mAppDetail.mBatteryHelper = mBatteryStatsHelper;
459        mAppDetail.mSipper = mBatterySipper;
460
461        assertThat(mAppDetail.isBatteryStatsAvailable()).isTrue();
462    }
463
464    @Test
465    public void isBatteryStatsAvailable_parametersNull_returnFalse() {
466        assertThat(mAppDetail.isBatteryStatsAvailable()).isFalse();
467    }
468
469    @Test
470    public void handleDisableable_appIsHomeApp_buttonShouldNotWork() {
471        final ApplicationInfo info = new ApplicationInfo();
472        info.packageName = "pkg";
473        info.enabled = true;
474        final AppEntry appEntry = mock(AppEntry.class);
475        appEntry.info = info;
476        final HashSet<String> homePackages = new HashSet<>();
477        homePackages.add(info.packageName);
478
479        ReflectionHelpers.setField(mAppDetail, "mHomePackages", homePackages);
480        ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
481        final Button button = mock(Button.class);
482
483        assertThat(mAppDetail.handleDisableable(button)).isFalse();
484        verify(button).setText(R.string.disable_text);
485    }
486
487    @Test
488    @Config(shadows = ShadowUtils.class)
489    public void handleDisableable_appIsEnabled_buttonShouldWork() {
490        final ApplicationInfo info = new ApplicationInfo();
491        info.packageName = "pkg";
492        info.enabled = true;
493        info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
494
495        final AppEntry appEntry = mock(AppEntry.class);
496        appEntry.info = info;
497        when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()).thenReturn(
498                new HashSet<>());
499
500        ReflectionHelpers.setField(mAppDetail, "mApplicationFeatureProvider",
501                mFeatureFactory.applicationFeatureProvider);
502        ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
503        final Button button = mock(Button.class);
504
505        assertThat(mAppDetail.handleDisableable(button)).isTrue();
506        verify(button).setText(R.string.disable_text);
507    }
508
509    @Test
510    @Config(shadows = ShadowUtils.class)
511    public void handleDisableable_appIsEnabledAndInKeepEnabledWhitelist_buttonShouldNotWork() {
512        final ApplicationInfo info = new ApplicationInfo();
513        info.packageName = "pkg";
514        info.enabled = true;
515        info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
516
517        final AppEntry appEntry = mock(AppEntry.class);
518        appEntry.info = info;
519
520        final HashSet<String> packages = new HashSet<>();
521        packages.add(info.packageName);
522        when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()).thenReturn(
523                packages);
524
525        ReflectionHelpers.setField(mAppDetail, "mApplicationFeatureProvider",
526                mFeatureFactory.applicationFeatureProvider);
527        ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
528
529        final Button button = mock(Button.class);
530
531        assertThat(mAppDetail.handleDisableable(button)).isFalse();
532        verify(button).setText(R.string.disable_text);
533    }
534
535    @Test
536    public void testRestartBatteryStatsLoader() {
537        doReturn(mLoaderManager).when(mAppDetail).getLoaderManager();
538
539        mAppDetail.restartBatteryStatsLoader();
540
541        verify(mLoaderManager).restartLoader(InstalledAppDetails.LOADER_BATTERY, Bundle.EMPTY,
542                mAppDetail.mBatteryCallbacks);
543    }
544
545    @Implements(Utils.class)
546    public static class ShadowUtils {
547        @Implementation
548        public static boolean isSystemPackage(Resources resources, PackageManager pm,
549                PackageInfo pkg) {
550            return false;
551        }
552    }
553}
554