Fix NPE crash when opening the app info from shortcut suggestion

It occurs NPE in invoking refreshUi() of AppButtonsPreferenceController
when user fully install the instant app from google play and then
directly open app info from the shortcut suggestion in launcher.

Root cause:
AppButtonsPreferenceController.refreshUi() will be invoked when user
directly open app info from the shortcut suggestion in launcher. In
refreshUi(), we will update the information of button preference, but
the preferences will not be initialized if device existed an instant
version for the app.

Solution:
Check button preference and initial them if need in refreshUi().

Fixes: 137854835
Test: visual, robotests
Change-Id: Id5c3e53b9db2683cab970c10eace7925d889eea3
This commit is contained in:
Yanting Yang
2019-08-06 22:45:52 +08:00
parent 7a2f3dd8a7
commit 9dc0a45fd8
2 changed files with 49 additions and 12 deletions

View File

@@ -116,6 +116,7 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
private Intent mAppLaunchIntent;
private ApplicationsState.Session mSession;
private RestrictedLockUtils.EnforcedAdmin mAppsControlDisallowedAdmin;
private PreferenceScreen mScreen;
private boolean mUpdatedSysApp = false;
private boolean mListeningToPackageRemove = false;
@@ -167,19 +168,9 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mScreen = screen;
if (isAvailable()) {
mButtonsPref = ((ActionButtonsPreference) screen.findPreference(
KEY_ACTION_BUTTONS))
.setButton1Text(R.string.launch_instant_app)
.setButton1Icon(R.drawable.ic_settings_open)
.setButton1OnClickListener(v -> launchApplication())
.setButton2Text(R.string.uninstall_text)
.setButton2Icon(R.drawable.ic_settings_delete)
.setButton2OnClickListener(new UninstallAndDisableButtonListener())
.setButton3Text(R.string.force_stop)
.setButton3Icon(R.drawable.ic_settings_force_stop)
.setButton3OnClickListener(new ForceStopButtonListener())
.setButton3Enabled(false);
initButtonPreference();
}
}
@@ -663,6 +654,11 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
}
}
// When the app was installed from instant state, buttons preferences could be null.
if (mButtonsPref == null) {
initButtonPreference();
mButtonsPref.setVisible(true);
}
updateOpenButton();
updateUninstallButton();
updateForceStopButton();
@@ -670,6 +666,21 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
return true;
}
private void initButtonPreference() {
mButtonsPref = ((ActionButtonsPreference) mScreen.findPreference(
KEY_ACTION_BUTTONS))
.setButton1Text(R.string.launch_instant_app)
.setButton1Icon(R.drawable.ic_settings_open)
.setButton1OnClickListener(v -> launchApplication())
.setButton2Text(R.string.uninstall_text)
.setButton2Icon(R.drawable.ic_settings_delete)
.setButton2OnClickListener(new UninstallAndDisableButtonListener())
.setButton3Text(R.string.force_stop)
.setButton3Icon(R.drawable.ic_settings_force_stop)
.setButton3OnClickListener(new ForceStopButtonListener())
.setButton3Enabled(false);
}
private void startListeningToPackageRemove() {
if (mListeningToPackageRemove) {
return;

View File

@@ -50,6 +50,8 @@ import android.os.UserManager;
import android.util.ArraySet;
import android.view.View;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
@@ -116,6 +118,8 @@ public class AppButtonsPreferenceControllerTest {
private UserManager mUserManager;
@Mock
private PackageInfo mPackageInfo;
@Mock
private PreferenceScreen mScreen;
private Context mContext;
private Intent mUninstallIntent;
@@ -471,6 +475,20 @@ public class AppButtonsPreferenceControllerTest {
assertThat(mController.refreshUi()).isFalse();
}
@Test
public void refreshUi_buttonPreferenceNull_shouldNotCrash()
throws PackageManager.NameNotFoundException {
doReturn(AppButtonsPreferenceController.AVAILABLE)
.when(mController).getAvailabilityStatus();
doReturn(mPackageInfo).when(mPackageManger).getPackageInfo(anyString(), anyInt());
doReturn(mButtonPrefs).when(mScreen).findPreference(anyString());
mController.displayPreference(mScreen);
mController.mButtonsPref = null;
// Should not crash in this method
assertThat(mController.refreshUi()).isTrue();
}
@Test
public void onPackageListChanged_available_shouldRefreshUi() {
doReturn(AppButtonsPreferenceController.AVAILABLE)
@@ -545,11 +563,19 @@ public class AppButtonsPreferenceControllerTest {
private ActionButtonsPreference createMock() {
final ActionButtonsPreference pref = mock(ActionButtonsPreference.class);
when(pref.setButton1Text(anyInt())).thenReturn(pref);
when(pref.setButton1Icon(anyInt())).thenReturn(pref);
when(pref.setButton1Enabled(anyBoolean())).thenReturn(pref);
when(pref.setButton1OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
when(pref.setButton2Text(anyInt())).thenReturn(pref);
when(pref.setButton2Icon(anyInt())).thenReturn(pref);
when(pref.setButton2Enabled(anyBoolean())).thenReturn(pref);
when(pref.setButton2Visible(anyBoolean())).thenReturn(pref);
when(pref.setButton2OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
when(pref.setButton3Text(anyInt())).thenReturn(pref);
when(pref.setButton3Icon(anyInt())).thenReturn(pref);
when(pref.setButton3Enabled(anyBoolean())).thenReturn(pref);
when(pref.setButton3OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
return pref;
}