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

Commit 1e55fa42 authored by Sumedh Sen's avatar Sumedh Sen
Browse files

Handle uninstall abort case and show appropriate dialog

When an uninstall is aborted due to app not being present or permission, appOp denial, show appropriate dialog and handle user action on dismissing the dialog.

Bug: 182205982
Test: builds successfully
Test: No CTS Tests. Flag to use new app is turned off by default

Change-Id: I0a4fbf04e6e33e2e05f38fd7d82f7a5218b59033
parent 0eb575e7
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
@@ -19,14 +19,20 @@ package com.android.packageinstaller.v2.ui;
import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
import com.android.packageinstaller.v2.model.UninstallRepository;
import com.android.packageinstaller.v2.model.UninstallRepository.CallerInfo;
import com.android.packageinstaller.v2.model.uninstallstagedata.UninstallAborted;
import com.android.packageinstaller.v2.model.uninstallstagedata.UninstallStage;
import com.android.packageinstaller.v2.ui.fragments.UninstallErrorFragment;
import com.android.packageinstaller.v2.viewmodel.UninstallViewModel;
import com.android.packageinstaller.v2.viewmodel.UninstallViewModelFactory;

@@ -37,9 +43,11 @@ public class UninstallLaunch extends FragmentActivity implements UninstallAction
    public static final String EXTRA_CALLING_ACTIVITY_NAME =
        UninstallLaunch.class.getPackageName() + ".callingActivityName";
    public static final String TAG = UninstallLaunch.class.getSimpleName();
    private static final String TAG_DIALOG = "dialog";

    private UninstallViewModel mUninstallViewModel;
    private UninstallRepository mUninstallRepository;
    private FragmentManager mFragmentManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -49,6 +57,8 @@ public class UninstallLaunch extends FragmentActivity implements UninstallAction
        // be stale, if e.g. the app was uninstalled while the activity was destroyed.
        super.onCreate(null);

        mFragmentManager = getSupportFragmentManager();

        mUninstallRepository = new UninstallRepository(getApplicationContext());
        mUninstallViewModel = new ViewModelProvider(this,
            new UninstallViewModelFactory(this.getApplication(), mUninstallRepository)).get(
@@ -69,6 +79,42 @@ public class UninstallLaunch extends FragmentActivity implements UninstallAction
     * uninstall stage
     */
    private void onUninstallStageChange(UninstallStage uninstallStage) {
        if (uninstallStage.getStageCode() == UninstallStage.STAGE_ABORTED) {
            UninstallAborted aborted = (UninstallAborted) uninstallStage;
            if (aborted.getAbortReason() == UninstallAborted.ABORT_REASON_APP_UNAVAILABLE ||
                aborted.getAbortReason() == UninstallAborted.ABORT_REASON_USER_NOT_ALLOWED) {
                UninstallErrorFragment errorDialog = new UninstallErrorFragment(aborted);
                showDialogInner(errorDialog);
            } else {
                setResult(aborted.getActivityResultCode(), null, true);
            }
        } else {
            Log.e(TAG, "Invalid stage: " + uninstallStage.getStageCode());
            showDialogInner(null);
        }
    }

    /**
     * Replace any visible dialog by the dialog returned by InstallRepository
     *
     * @param newDialog The new dialog to display
     */
    private void showDialogInner(DialogFragment newDialog) {
        DialogFragment currentDialog = (DialogFragment) mFragmentManager.findFragmentByTag(
            TAG_DIALOG);
        if (currentDialog != null) {
            currentDialog.dismissAllowingStateLoss();
        }
        if (newDialog != null) {
            newDialog.show(mFragmentManager, TAG_DIALOG);
        }
    }

    public void setResult(int resultCode, Intent data, boolean shouldFinish) {
        super.setResult(resultCode, data);
        if (shouldFinish) {
            finish();
        }
    }

    @Override
@@ -77,5 +123,6 @@ public class UninstallLaunch extends FragmentActivity implements UninstallAction

    @Override
    public void onNegativeResponse() {
        setResult(Activity.RESULT_FIRST_USER, null, true);
    }
}
+68 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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
 *
 *      https://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.packageinstaller.v2.ui.fragments;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import com.android.packageinstaller.R;
import com.android.packageinstaller.v2.model.uninstallstagedata.UninstallAborted;
import com.android.packageinstaller.v2.ui.UninstallActionListener;

/**
 * Dialog to show when an app cannot be uninstalled
 */
public class UninstallErrorFragment extends DialogFragment {

    private final UninstallAborted mDialogData;
    private UninstallActionListener mUninstallActionListener;

    public UninstallErrorFragment(UninstallAborted dialogData) {
        mDialogData = dialogData;
    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        mUninstallActionListener = (UninstallActionListener) context;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(requireContext())
            .setMessage(mDialogData.getDialogTextResource())
            .setNegativeButton(R.string.ok,
                (dialogInt, which) -> mUninstallActionListener.onNegativeResponse());

        if (mDialogData.getDialogTitleResource() != 0) {
            builder.setTitle(mDialogData.getDialogTitleResource());
        }
        return builder.create();
    }

    @Override
    public void onCancel(@NonNull DialogInterface dialog) {
        super.onCancel(dialog);
        mUninstallActionListener.onNegativeResponse();
    }
}