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

Commit f176175f authored by Doris Ling's avatar Doris Ling
Browse files

Move clear instant app dialog logic out of AppInfoDashboardFragment.

- refactor AppInfoDashboardFragment and move the clear instant app dialog
handling into instant app button controller.
- move the dialog fragment to be a stand-alone class instead of inner
class.

Change-Id: I51c045938f3fd1db73b4b9f7e0311a51df599a29
Fixes: 110102457
Test: make RunSettingsRoboTests
parent 701d9a0e
Loading
Loading
Loading
Loading
+3 −50
Original line number Diff line number Diff line
@@ -19,9 +19,6 @@ package com.android.settings.applications.appinfo;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -95,10 +92,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
    static final int LOADER_STORAGE = 3;
    static final int LOADER_BATTERY = 4;

    // Dialog identifiers used in showDialog
    private static final int DLG_BASE = 0;
    static final int DLG_CLEAR_INSTANT_APP = DLG_BASE + 1;

    public static final String ARG_PACKAGE_NAME = "package";
    public static final String ARG_PACKAGE_UID = "uid";

@@ -419,7 +412,9 @@ public class AppInfoDashboardFragment extends DashboardFragment
        for (Callback callback : mCallbacks) {
            callback.refreshUi();
        }
        if (mAppButtonsPreferenceController.isAvailable()) {
            mAppButtonsPreferenceController.refreshUi();
        }

        if (!mInitialized) {
            // First time init: are we displaying an uninstalled app?
@@ -447,11 +442,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
        return true;
    }

    @VisibleForTesting
    AlertDialog createDialog(int id, int errorCode) {
        return mInstantAppButtonPreferenceController.createDialog(id);
    }

    private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
        stopListeningToPackageRemove();
        // Create new intent to launch Uninstaller activity
@@ -561,12 +551,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
        mFinishing = true;
    }

    void showDialogInner(int id, int moveErrorCode) {
        final DialogFragment newFragment = MyAlertDialogFragment.newInstance(id, moveErrorCode);
        newFragment.setTargetFragment(this, 0);
        newFragment.show(getFragmentManager(), "dialog " + id);
    }

    @Override
    public void onRunningStateChanged(boolean running) {
        // No op.
@@ -604,37 +588,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
        }
    }

    public static class MyAlertDialogFragment extends InstrumentedDialogFragment {

        private static final String ARG_ID = "id";

        @Override
        public int getMetricsCategory() {
            return MetricsEvent.DIALOG_APP_INFO_ACTION;
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            final int id = getArguments().getInt(ARG_ID);
            final int errorCode = getArguments().getInt("moveError");
            final Dialog dialog =
                    ((AppInfoDashboardFragment) getTargetFragment()).createDialog(id, errorCode);
            if (dialog == null) {
                throw new IllegalArgumentException("unknown id " + id);
            }
            return dialog;
        }

        public static MyAlertDialogFragment newInstance(int id, int errorCode) {
            final MyAlertDialogFragment dialogFragment = new MyAlertDialogFragment();
            final Bundle args = new Bundle();
            args.putInt(ARG_ID, id);
            args.putInt("moveError", errorCode);
            dialogFragment.setArguments(args);
            return dialogFragment;
        }
    }

    @VisibleForTesting
    void startListeningToPackageRemove() {
        if (mListeningToPackageRemove) {
+15 −0
Original line number Diff line number Diff line
/*
 * 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.settings.applications.appinfo;

import android.app.AlertDialog;
+80 −0
Original line number Diff line number Diff line
/*
 * 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.settings.applications.appinfo;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.UserHandle;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.overlay.FeatureFactory;

/**
 * Fragment to show the dialog for clearing the instant app.
 */
public class InstantAppButtonDialogFragment extends InstrumentedDialogFragment implements
        DialogInterface.OnClickListener {

    private static final String ARG_PACKAGE_NAME = "packageName";

    private String mPackageName;

    public static InstantAppButtonDialogFragment newInstance(String packageName) {
        final InstantAppButtonDialogFragment dialogFragment = new InstantAppButtonDialogFragment();
        final Bundle args = new Bundle(1);
        args.putString(ARG_PACKAGE_NAME, packageName);
        dialogFragment.setArguments(args);
        return dialogFragment;
    }

    @Override
    public int getMetricsCategory() {
        return MetricsEvent.DIALOG_APP_INFO_ACTION;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final Bundle arguments = getArguments();
        mPackageName = arguments.getString(ARG_PACKAGE_NAME);
        return createDialog();
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        final Context context = getContext();
        final PackageManager packageManager = context.getPackageManager();
        FeatureFactory.getFactory(context).getMetricsFeatureProvider()
            .action(context, MetricsEvent.ACTION_SETTINGS_CLEAR_INSTANT_APP, mPackageName);
        packageManager.deletePackageAsUser(mPackageName, null, 0, UserHandle.myUserId());
    }

    private AlertDialog createDialog() {
        AlertDialog confirmDialog = new AlertDialog.Builder(getContext())
            .setPositiveButton(R.string.clear_instant_app_data, this)
            .setNegativeButton(R.string.cancel, null)
            .setTitle(R.string.clear_instant_app_data)
            .setMessage(R.string.clear_instant_app_confirmation)
            .create();
        return confirmDialog;
    }

}
+10 −32
Original line number Diff line number Diff line
@@ -16,15 +16,13 @@

package com.android.settings.applications.appinfo;

import android.app.AlertDialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;

import androidx.preference.PreferenceScreen;
import android.text.TextUtils;
@@ -34,12 +32,10 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.Button;

import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.applications.AppStoreUtil;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -50,15 +46,13 @@ import com.android.settingslib.core.lifecycle.events.OnPrepareOptionsMenu;
import java.util.List;

public class InstantAppButtonsPreferenceController extends BasePreferenceController implements
        LifecycleObserver, OnCreateOptionsMenu, OnPrepareOptionsMenu, OnOptionsItemSelected,
        DialogInterface.OnClickListener {
        LifecycleObserver, OnCreateOptionsMenu, OnPrepareOptionsMenu, OnOptionsItemSelected {

    private static final String KEY_INSTANT_APP_BUTTONS = "instant_app_buttons";
    private static final String META_DATA_DEFAULT_URI = "default-url";

    private final AppInfoDashboardFragment mParent;
    private final String mPackageName;
    private final PackageManager mPackageManager;
    private String mLaunchUri;
    private LayoutPreference mPreference;
    private MenuItem mInstallMenu;
@@ -68,7 +62,6 @@ public class InstantAppButtonsPreferenceController extends BasePreferenceControl
        super(context, KEY_INSTANT_APP_BUTTONS);
        mParent = parent;
        mPackageName = packageName;
        mPackageManager = context.getPackageManager();
        mLaunchUri = getDefaultLaunchUri();
        if (lifecycle != null) {
            lifecycle.addObserver(this);
@@ -118,27 +111,6 @@ public class InstantAppButtonsPreferenceController extends BasePreferenceControl
        }
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        FeatureFactory.getFactory(mContext).getMetricsFeatureProvider()
            .action(mContext, MetricsEvent.ACTION_SETTINGS_CLEAR_INSTANT_APP, mPackageName);
        mPackageManager.deletePackageAsUser(
            mPackageName, null, 0, UserHandle.myUserId());
    }

    AlertDialog createDialog(int id) {
        if (id == AppInfoDashboardFragment.DLG_CLEAR_INSTANT_APP) {
            AlertDialog confirmDialog = new AlertDialog.Builder(mContext)
                .setPositiveButton(R.string.clear_instant_app_data, this)
                .setNegativeButton(R.string.cancel, null)
                .setTitle(R.string.clear_instant_app_data)
                .setMessage(mContext.getString(R.string.clear_instant_app_confirmation))
                .create();
            return confirmDialog;
        }
        return null;
    }

    private void initButtons(View view) {
        final Button installButton = view.findViewById(R.id.install);
        final Button clearDataButton = view.findViewById(R.id.clear_data);
@@ -160,8 +132,14 @@ public class InstantAppButtonsPreferenceController extends BasePreferenceControl
                installButton.setEnabled(false);
            }
        }
        clearDataButton.setOnClickListener(
            v -> mParent.showDialogInner(mParent.DLG_CLEAR_INSTANT_APP, 0));
        clearDataButton.setOnClickListener(v -> showDialog());
    }

    private void showDialog() {
        final DialogFragment newFragment =
            InstantAppButtonDialogFragment.newInstance(mPackageName);
        newFragment.setTargetFragment(mParent, 0);
        newFragment.show(mParent.getFragmentManager(), KEY_INSTANT_APP_BUTTONS);
    }

    private String getDefaultLaunchUri() {
+87 −0
Original line number Diff line number Diff line
/*
 * 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.settings.applications.appinfo;

import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowAlertDialog;
import org.robolectric.shadows.ShadowDialog;
import org.robolectric.util.FragmentTestUtil;

@RunWith(SettingsRobolectricTestRunner.class)
public class InstantAppButtonDialogFragmentTest {

    private static final String TEST_PACKAGE = "testPackage";

    private InstantAppButtonDialogFragment mFragment;
    private Context mContext;

    @Before
    public void setUp() {
        mContext = spy(RuntimeEnvironment.application);
        mFragment = spy(InstantAppButtonDialogFragment.newInstance(TEST_PACKAGE));
        doReturn(mContext).when(mFragment).getContext();
    }

    @Test
    public void onClick_shouldDeleteApp() {
        final PackageManager packageManager = mock(PackageManager.class);
        when(mContext.getPackageManager()).thenReturn(packageManager);
        FragmentTestUtil.startFragment(mFragment);

        mFragment.onClick(null /* dialog */, 0  /* which */);

        verify(packageManager)
            .deletePackageAsUser(eq(TEST_PACKAGE), any(), anyInt(), anyInt());
    }

    @Test
    public void onCreateDialog_clearAppDialog_shouldShowClearAppDataConfirmation() {
        FragmentTestUtil.startFragment(mFragment);

        final AlertDialog dialog = (AlertDialog) ShadowDialog.getLatestDialog();
        assertThat(dialog).isNotNull();
        final ShadowAlertDialog shadowDialog = shadowOf(dialog);

        assertThat(shadowDialog.getMessage()).isEqualTo(
                mContext.getString(R.string.clear_instant_app_confirmation));
        assertThat(shadowDialog.getTitle()).isEqualTo(
                mContext.getString(R.string.clear_instant_app_data));
        assertThat(dialog.getButton(DialogInterface.BUTTON_POSITIVE).getText()).isEqualTo(
                mContext.getString(R.string.clear_instant_app_data));
        assertThat(dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getText()).isEqualTo(
                mContext.getString(R.string.cancel));
    }
}
Loading