Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aacf7bd6 authored by Edward Cunningham's avatar Edward Cunningham Committed by Android (Google) Code Review
Browse files

Merge "Improve installer attribution in App Info." into sc-dev

parents 990b405e faf44124
Loading
Loading
Loading
Loading
+24 −6
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@ package com.android.settings.applications;

import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.util.Log;

@@ -31,15 +34,30 @@ public class AppStoreUtil {
                .setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
    }

    // Returns the package name of the app which installed a given packageName, if one is
    // available.
    // Returns the package name of the app that we consider to be the user-visible 'installer'
    // of given packageName, if one is available.
    public static String getInstallerPackageName(Context context, String packageName) {
        String installerPackageName = null;
        String installerPackageName;
        try {
            installerPackageName =
                    context.getPackageManager().getInstallerPackageName(packageName);
        } catch (IllegalArgumentException e) {
            InstallSourceInfo source =
                    context.getPackageManager().getInstallSourceInfo(packageName);
            // By default, use the installing package name.
            installerPackageName = source.getInstallingPackageName();
            // Use the recorded originating package name only if the initiating package is a system
            // app (eg. Package Installer). The originating package is not verified by the platform,
            // so we choose to ignore this when supplied by a non-system app.
            String originatingPackageName = source.getOriginatingPackageName();
            String initiatingPackageName = source.getInitiatingPackageName();
            if (originatingPackageName != null && initiatingPackageName != null) {
                ApplicationInfo ai = context.getPackageManager().getApplicationInfo(
                        initiatingPackageName, 0);
                if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                    installerPackageName = originatingPackageName;
                }
            }
        } catch (NameNotFoundException e) {
            Log.e(LOG_TAG, "Exception while retrieving the package installer of " + packageName, e);
            installerPackageName = null;
        }
        return installerPackageName;
    }
+96 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.settings.applications;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageManager;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;

@RunWith(RobolectricTestRunner.class)
public class AppStoreUtilTest {

    private static final String PACKAGE_NAME = "com.android.app";
    private static final String INSTALLING_PACKAGE_NAME = "com.android.installing";
    private static final String INITIATING_PACKAGE_NAME = "com.android.initiating";
    private static final String ORIGINATING_PACKAGE_NAME = "com.android.originating";

    @Mock
    private PackageManager mPackageManager;
    @Mock
    private ApplicationInfo mInitiatingAppInfo;
    @Mock
    private InstallSourceInfo mInstallSourceInfo;

    private Context mContext;

    @Before
    public void setUp() throws PackageManager.NameNotFoundException {
        MockitoAnnotations.initMocks(this);
        mContext = spy(RuntimeEnvironment.application);
        when(mContext.getPackageManager()).thenReturn(mPackageManager);
        when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
        when(mInstallSourceInfo.getInstallingPackageName()).thenReturn(INSTALLING_PACKAGE_NAME);
        when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn(INITIATING_PACKAGE_NAME);
        when(mInstallSourceInfo.getOriginatingPackageName()).thenReturn(ORIGINATING_PACKAGE_NAME);
        when(mPackageManager.getApplicationInfo(eq(INITIATING_PACKAGE_NAME), anyInt()))
                .thenReturn(mInitiatingAppInfo);
    }

    @Test
    public void getInstallerPackageName_hasOriginatingByNonSystem_shouldReturnInstalling() {
        assertThat(AppStoreUtil.getInstallerPackageName(mContext, PACKAGE_NAME))
                .isEqualTo(INSTALLING_PACKAGE_NAME);
    }

    @Test
    public void getInstallerPackageName_hasOriginatingBySystem_shouldReturnOriginating() {
        mInitiatingAppInfo.flags = ApplicationInfo.FLAG_SYSTEM;
        assertThat(AppStoreUtil.getInstallerPackageName(mContext, PACKAGE_NAME))
                .isEqualTo(ORIGINATING_PACKAGE_NAME);
    }

    @Test
    public void getInstallerPackageName_noInitiating_shouldReturnInstalling() {
        when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn(null);
        assertThat(AppStoreUtil.getInstallerPackageName(mContext, PACKAGE_NAME))
                .isEqualTo(INSTALLING_PACKAGE_NAME);
    }

    @Test
    public void getInstallerPackageName_noOriginating_shouldReturnInstalling() {
        when(mInstallSourceInfo.getOriginatingPackageName()).thenReturn(null);
        assertThat(AppStoreUtil.getInstallerPackageName(mContext, PACKAGE_NAME))
                .isEqualTo(INSTALLING_PACKAGE_NAME);
    }
}
+5 −1
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -60,6 +61,8 @@ public class AppInstallerInfoPreferenceControllerTest {
    @Mock
    private ApplicationInfo mAppInfo;
    @Mock
    private InstallSourceInfo mInstallSourceInfo;
    @Mock
    private AppInfoDashboardFragment mFragment;
    @Mock
    private Preference mPreference;
@@ -74,7 +77,8 @@ public class AppInstallerInfoPreferenceControllerTest {
        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
        when(mContext.getPackageManager()).thenReturn(mPackageManager);
        final String installerPackage = "Installer1";
        when(mPackageManager.getInstallerPackageName(anyString())).thenReturn(installerPackage);
        when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
        when(mInstallSourceInfo.getInstallingPackageName()).thenReturn(installerPackage);
        when(mPackageManager.getApplicationInfo(eq(installerPackage), anyInt()))
                .thenReturn(mAppInfo);
        mController = new AppInstallerInfoPreferenceController(mContext, "test_key");
+19 −25
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -87,7 +88,7 @@ public class InstantAppButtonsPreferenceControllerTest {
    private InstantAppButtonsPreferenceController mController;

    @Before
    public void setUp() {
    public void setUp() throws PackageManager.NameNotFoundException {
        MockitoAnnotations.initMocks(this);
        mContext = spy(RuntimeEnvironment.application);
        when(mContext.getPackageManager()).thenReturn(mPackageManager);
@@ -107,6 +108,10 @@ public class InstantAppButtonsPreferenceControllerTest {
        when(mPreference.getKey()).thenReturn("instant_app_buttons");
        mScreen.addPreference(mPreference);
        when(mPreference.findViewById(R.id.instant_app_button_container)).thenReturn(buttons);
        final InstallSourceInfo installSourceInfo = mock(InstallSourceInfo.class);
        when(mPackageManager.getInstallSourceInfo(TEST_AIA_PACKAGE_NAME))
            .thenReturn(installSourceInfo);
        when(installSourceInfo.getInstallingPackageName()).thenReturn(TEST_INSTALLER_PACKAGE_NAME);
    }

    @Test
@@ -165,12 +170,7 @@ public class InstantAppButtonsPreferenceControllerTest {
    @Test
    public void onPrepareOptionsMenu_hasAppStoreLink_shoulNotDisableInstallInstantAppMenu() {
        ReflectionHelpers.setField(mController, "mLaunchUri", "www.test.launch");
        final ResolveInfo resolveInfo = mock(ResolveInfo.class);
        final ActivityInfo activityInfo = mock(ActivityInfo.class);
        resolveInfo.activityInfo = activityInfo;
        activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME;
        activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME;
        when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
        initAppStoreInfo();
        final Menu menu = mock(Menu.class);
        final MenuItem menuItem = mock(MenuItem.class);
        when(menu.findItem(AppInfoDashboardFragment.INSTALL_INSTANT_APP_MENU)).thenReturn(menuItem);
@@ -191,12 +191,7 @@ public class InstantAppButtonsPreferenceControllerTest {

    @Test
    public void onOptionsItemSelected_shouldOpenAppStore() {
        final ResolveInfo resolveInfo = mock(ResolveInfo.class);
        final ActivityInfo activityInfo = mock(ActivityInfo.class);
        resolveInfo.activityInfo = activityInfo;
        activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME;
        activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME;
        when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
        initAppStoreInfo();
        mController.displayPreference(mScreen);
        final ComponentName componentName =
            new ComponentName(TEST_INSTALLER_PACKAGE_NAME, TEST_INSTALLER_ACTIVITY_NAME);
@@ -235,12 +230,7 @@ public class InstantAppButtonsPreferenceControllerTest {

    @Test
    public void displayPreference_hasAppStoreLink_shoulSetClickListenerForInstallButton() {
        final ResolveInfo resolveInfo = mock(ResolveInfo.class);
        final ActivityInfo activityInfo = mock(ActivityInfo.class);
        resolveInfo.activityInfo = activityInfo;
        activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME;
        activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME;
        when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
        initAppStoreInfo();

        mController.displayPreference(mScreen);

@@ -272,12 +262,7 @@ public class InstantAppButtonsPreferenceControllerTest {

    @Test
    public void clickInstallButton_shouldOpenAppStore() {
        final ResolveInfo resolveInfo = mock(ResolveInfo.class);
        final ActivityInfo activityInfo = mock(ActivityInfo.class);
        resolveInfo.activityInfo = activityInfo;
        activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME;
        activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME;
        when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
        initAppStoreInfo();
        mController.displayPreference(mScreen);
        final ComponentName componentName =
            new ComponentName(TEST_INSTALLER_PACKAGE_NAME, TEST_INSTALLER_ACTIVITY_NAME);
@@ -302,4 +287,13 @@ public class InstantAppButtonsPreferenceControllerTest {
        verify(fragmentTransaction).add(any(InstantAppButtonDialogFragment.class),
            eq("instant_app_buttons"));
    }

    private void initAppStoreInfo() {
        final ResolveInfo resolveInfo = mock(ResolveInfo.class);
        final ActivityInfo activityInfo = mock(ActivityInfo.class);
        resolveInfo.activityInfo = activityInfo;
        activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME;
        activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME;
        when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
    }
}