From 921687cbc404090b6cdbf30bef797c12fc56a3aa Mon Sep 17 00:00:00 2001 From: Dake Gu Date: Tue, 20 Feb 2018 17:03:37 -0800 Subject: [PATCH] SettingsLib: Move DefaultAppInfo CandidateInfo from Settings Bug: 3600711 Test: DefaultAppInfoTest moved from SettingsLib m RunSettingsLibRoboTests Change-Id: Iba7f60aacaf97774e8f120cccaacd1d1389fd227 --- .../applications/DefaultAppInfo.java | 153 ++++++++++++++++++ .../settingslib/widget/CandidateInfo.java | 37 +++++ .../wrapper/PackageManagerWrapper.java | 7 + .../applications/DefaultAppInfoTest.java | 98 +++++++++++ 4 files changed, 295 insertions(+) create mode 100644 packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java create mode 100644 packages/SettingsLib/src/com/android/settingslib/widget/CandidateInfo.java create mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java b/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java new file mode 100644 index 0000000000000..246ca474da327 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2017 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.settingslib.applications; + +import android.app.AppGlobals; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.ComponentInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.IconDrawableFactory; + +import com.android.settingslib.widget.CandidateInfo; +import com.android.settingslib.wrapper.PackageManagerWrapper; + +/** + * Data model representing an app in DefaultAppPicker UI. + */ +public class DefaultAppInfo extends CandidateInfo { + + public final int userId; + public final ComponentName componentName; + public final PackageItemInfo packageItemInfo; + public final String summary; + protected final PackageManagerWrapper mPm; + private final Context mContext; + + public DefaultAppInfo(Context context, PackageManagerWrapper pm, int uid, ComponentName cn) { + this(context, pm, uid, cn, null /* summary */, true /* enabled */); + } + + public DefaultAppInfo(Context context, PackageManagerWrapper pm, PackageItemInfo info) { + this(context, pm, info, null /* summary */, true /* enabled */); + } + + public DefaultAppInfo(Context context, PackageManagerWrapper pm, int uid, ComponentName cn, + String summary, boolean enabled) { + super(enabled); + mContext = context; + mPm = pm; + packageItemInfo = null; + userId = uid; + componentName = cn; + this.summary = summary; + } + + public DefaultAppInfo(Context context, PackageManagerWrapper pm, PackageItemInfo info, + String summary, boolean enabled) { + super(enabled); + mContext = context; + mPm = pm; + userId = UserHandle.myUserId(); + packageItemInfo = info; + componentName = null; + this.summary = summary; + } + + @Override + public CharSequence loadLabel() { + if (componentName != null) { + try { + final ComponentInfo componentInfo = getComponentInfo(); + if (componentInfo != null) { + return componentInfo.loadLabel(mPm.getPackageManager()); + } else { + final ApplicationInfo appInfo = mPm.getApplicationInfoAsUser( + componentName.getPackageName(), 0, userId); + return appInfo.loadLabel(mPm.getPackageManager()); + } + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } else if (packageItemInfo != null) { + return packageItemInfo.loadLabel(mPm.getPackageManager()); + } else { + return null; + } + + } + + @Override + public Drawable loadIcon() { + final IconDrawableFactory factory = IconDrawableFactory.newInstance(mContext); + if (componentName != null) { + try { + final ComponentInfo componentInfo = getComponentInfo(); + final ApplicationInfo appInfo = mPm.getApplicationInfoAsUser( + componentName.getPackageName(), 0, userId); + if (componentInfo != null) { + return factory.getBadgedIcon(componentInfo, appInfo, userId); + } else { + return factory.getBadgedIcon(appInfo); + } + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } + if (packageItemInfo != null) { + try { + final ApplicationInfo appInfo = mPm.getApplicationInfoAsUser( + packageItemInfo.packageName, 0, userId); + return factory.getBadgedIcon(packageItemInfo, appInfo, userId); + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } else { + return null; + } + } + + @Override + public String getKey() { + if (componentName != null) { + return componentName.flattenToString(); + } else if (packageItemInfo != null) { + return packageItemInfo.packageName; + } else { + return null; + } + } + + private ComponentInfo getComponentInfo() { + try { + ComponentInfo componentInfo = AppGlobals.getPackageManager().getActivityInfo( + componentName, 0, userId); + if (componentInfo == null) { + componentInfo = AppGlobals.getPackageManager().getServiceInfo( + componentName, 0, userId); + } + return componentInfo; + } catch (RemoteException e) { + return null; + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/CandidateInfo.java b/packages/SettingsLib/src/com/android/settingslib/widget/CandidateInfo.java new file mode 100644 index 0000000000000..cdb4ffd6e1f9b --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/widget/CandidateInfo.java @@ -0,0 +1,37 @@ +/* + * 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.settingslib.widget; + +import android.graphics.drawable.Drawable; + +/** + * Base class for defining a selectable item in UI. + */ +public abstract class CandidateInfo { + + public final boolean enabled; + + public CandidateInfo(boolean enabled) { + this.enabled = enabled; + } + + public abstract CharSequence loadLabel(); + + public abstract Drawable loadIcon(); + + public abstract String getKey(); +} diff --git a/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java b/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java index b1f3f3ce43005..235daf23a6642 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java +++ b/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java @@ -129,6 +129,13 @@ public class PackageManagerWrapper { return mPm.queryIntentServicesAsUser(intent, i, user); } + /** + * Calls {@code PackageManager.queryIntentServices} + */ + public List queryIntentServices(Intent intent, int i) { + return mPm.queryIntentServices(intent, i); + } + /** * Calls {@code PackageManager.replacePreferredActivity} */ diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java new file mode 100644 index 0000000000000..6a161d0a645cb --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2017 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.settingslib.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.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; +import com.android.settingslib.wrapper.PackageManagerWrapper; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsLibRobolectricTestRunner.class) +public class DefaultAppInfoTest { + + @Mock + private PackageItemInfo mPackageItemInfo; + @Mock + private ComponentName mComponentName; + @Mock + private PackageManager mPackageManager; + @Mock + private PackageManagerWrapper mPackageManagerWrapper; + @Mock + private ApplicationInfo mApplicationInfo; + @Mock + private Drawable mIcon; + + private Context mContext; + private DefaultAppInfo mInfo; + + @Before + public void setUp() throws PackageManager.NameNotFoundException { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mPackageManager).when(mContext).getPackageManager(); + when(mPackageManagerWrapper.getPackageManager()).thenReturn(mPackageManager); + when(mPackageManagerWrapper.getApplicationInfoAsUser(anyString(), anyInt(), + anyInt())).thenReturn(mApplicationInfo); + when(mPackageManager.loadUnbadgedItemIcon(mPackageItemInfo, mApplicationInfo)).thenReturn( + mIcon); + } + + @Test + public void initInfoWithActivityInfo_shouldLoadInfo() { + mPackageItemInfo.packageName = "test"; + mInfo = new DefaultAppInfo(mContext, mPackageManagerWrapper, mPackageItemInfo); + mInfo.loadLabel(); + Drawable icon = mInfo.loadIcon(); + + assertThat(mInfo.getKey()).isEqualTo(mPackageItemInfo.packageName); + assertThat(icon).isNotNull(); + verify(mPackageItemInfo).loadLabel(mPackageManager); + } + + @Test + public void initInfoWithComponent_shouldLoadInfo() { + when(mComponentName.getPackageName()).thenReturn("com.android.settings"); + + mInfo = new DefaultAppInfo(mContext, mPackageManagerWrapper, 0 /* uid */, mComponentName); + mInfo.getKey(); + + verify(mComponentName).flattenToString(); + } +}