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

Commit 0d5adbee authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I490f7153,I2bb5380e into main

* changes:
  [PM] Support better transition in PIA V2 (4/N)
  [PM] Support better transition in PIA V2 (3/N)
parents 10cf838f c08efc96
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -53,17 +53,7 @@ object PackageUtil {
    private const val SPLIT_APK_SUFFIX = ".apk"
    const val localLogv = false

    const val ARGS_ABORT_REASON: String = "abort_reason"
    const val ARGS_APP_DATA_SIZE: String = "app_data_size"
    const val ARGS_APP_SNIPPET: String = "app_snippet"
    const val ARGS_BUTTON_TEXT: String = "button_text"
    const val ARGS_INSTALLER_LABEL: String = "installer_label"
    const val ARGS_INSTALLER_PACKAGE: String = "installer_pkg"
    const val ARGS_MESSAGE: String = "message"
    const val ARGS_PENDING_INTENT: String = "pending_intent"
    const val ARGS_REQUIRED_BYTES: String = "required_bytes"
    const val ARGS_TITLE: String = "title"
    const val ARGS_UNARCHIVAL_STATUS: String = "unarchival_status"

    /**
     * Determines if the UID belongs to the system downloads provider and returns the
+36 −14
Original line number Diff line number Diff line
@@ -34,12 +34,9 @@ import androidx.lifecycle.ViewModelProvider
import com.android.packageinstaller.R
import com.android.packageinstaller.v2.model.PackageUtil
import com.android.packageinstaller.v2.model.UnarchiveAborted
import com.android.packageinstaller.v2.model.UnarchiveError
import com.android.packageinstaller.v2.model.UnarchiveRepository
import com.android.packageinstaller.v2.model.UnarchiveStage
import com.android.packageinstaller.v2.model.UnarchiveUserActionRequired
import com.android.packageinstaller.v2.ui.fragments.UnarchiveConfirmationFragment
import com.android.packageinstaller.v2.ui.fragments.UnarchiveErrorFragment
import com.android.packageinstaller.v2.ui.fragments.UnarchiveFragment
import com.android.packageinstaller.v2.viewmodel.UnarchiveViewModel
import com.android.packageinstaller.v2.viewmodel.UnarchiveViewModelFactory

@@ -55,6 +52,7 @@ class UnarchiveLaunch : FragmentActivity(), UnarchiveActionListener {
        private val LOG_TAG = UnarchiveLaunch::class.java.simpleName

        private const val TAG_DIALOG = "dialog"
        private const val TAG_UNARCHIVE_DIALOG = "unarchive-dialog"

        private const val ACTION_UNARCHIVE_DIALOG: String =
            "com.android.intent.action.UNARCHIVE_DIALOG"
@@ -109,15 +107,11 @@ class UnarchiveLaunch : FragmentActivity(), UnarchiveActionListener {
            }

            UnarchiveStage.STAGE_USER_ACTION_REQUIRED -> {
                val uar = stage as UnarchiveUserActionRequired
                val confirmationDialog = UnarchiveConfirmationFragment.newInstance(uar)
                showDialogInner(confirmationDialog)
                showUnarchiveDialog()
            }

            UnarchiveStage.STAGE_ERROR -> {
                val error = stage as UnarchiveError
                val errorDialog = UnarchiveErrorFragment.newInstance(error)
                showDialogInner(errorDialog)
                showUnarchiveDialog()
            }
        }
    }
@@ -131,7 +125,7 @@ class UnarchiveLaunch : FragmentActivity(), UnarchiveActionListener {
        installerPkg: String?,
        pi: PendingIntent?
    ) {
        // Allow the error handling actvities to start in the background.
        // Allow the error handling activities to start in the background.
        val options = BroadcastOptions.makeBasic()
        options.setPendingIntentBackgroundActivityStartMode(
            ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
@@ -176,6 +170,13 @@ class UnarchiveLaunch : FragmentActivity(), UnarchiveActionListener {
                // Do nothing. The rest of the dialogs are purely informational.
            }
        }
        finish()
    }

    private fun showUnarchiveDialog() {
        val fragment = getUnarchiveFragment() ?: UnarchiveFragment()
        fragment.updateUI()
        showDialogInner(fragment, TAG_UNARCHIVE_DIALOG)
    }

    /**
@@ -184,8 +185,29 @@ class UnarchiveLaunch : FragmentActivity(), UnarchiveActionListener {
     * @param newDialog The new dialog to display
     */
    private fun showDialogInner(newDialog: DialogFragment?) {
        val currentDialog = fragmentManager!!.findFragmentByTag(TAG_DIALOG) as DialogFragment?
        currentDialog?.dismissAllowingStateLoss()
        newDialog?.show(fragmentManager!!, TAG_DIALOG)
        showDialogInner(newDialog, TAG_DIALOG)
    }

    private fun showDialogInner(newDialog: DialogFragment?, tag: String) {
        var currentTag: String? = null
        if (tag == TAG_UNARCHIVE_DIALOG) {
            if (getUnarchiveFragment() != null) {
                return
            }
            currentTag = TAG_DIALOG
        } else {
            currentTag = TAG_UNARCHIVE_DIALOG
        }

        val currentDialog = fragmentManager!!.findFragmentByTag(currentTag)
        if (currentDialog is DialogFragment) {
            currentDialog.dismissAllowingStateLoss()
        }
        newDialog?.show(fragmentManager!!, tag)
    }

    private fun getUnarchiveFragment(): UnarchiveFragment? {
        return (fragmentManager!!.findFragmentByTag(TAG_UNARCHIVE_DIALOG)
            ?: return null) as UnarchiveFragment?
    }
}
+35 −12
Original line number Diff line number Diff line
@@ -37,9 +37,7 @@ import com.android.packageinstaller.v2.model.UninstallFailed
import com.android.packageinstaller.v2.model.UninstallRepository
import com.android.packageinstaller.v2.model.UninstallStage
import com.android.packageinstaller.v2.model.UninstallSuccess
import com.android.packageinstaller.v2.model.UninstallUserActionRequired
import com.android.packageinstaller.v2.ui.fragments.UninstallConfirmationFragment
import com.android.packageinstaller.v2.ui.fragments.UninstallErrorFragment
import com.android.packageinstaller.v2.ui.fragments.UninstallationFragment
import com.android.packageinstaller.v2.viewmodel.UninstallViewModel
import com.android.packageinstaller.v2.viewmodel.UninstallViewModelFactory

@@ -52,6 +50,7 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener {
            UninstallLaunch::class.java.packageName + ".callingActivityName"
        private val LOG_TAG = UninstallLaunch::class.java.simpleName
        private const val TAG_DIALOG = "dialog"
        private const val TAG_UNINSTALLATION_DIALOG = "uninstallation-dialog"
        private const val ARGS_SAVED_INTENT = "saved_intent"
    }

@@ -112,8 +111,7 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener {
                    UninstallAborted.ABORT_REASON_APP_UNAVAILABLE,
                    UninstallAborted.ABORT_REASON_UNKNOWN,
                    UninstallAborted.ABORT_REASON_USER_NOT_ALLOWED -> {
                        val errorDialog = UninstallErrorFragment.newInstance(aborted)
                        showDialogInner(errorDialog)
                        showUninstallationDialog()
                    }

                    else -> {
@@ -123,9 +121,7 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener {
            }

            UninstallStage.STAGE_USER_ACTION_REQUIRED -> {
                val uar = uninstallStage as UninstallUserActionRequired
                val confirmationDialog = UninstallConfirmationFragment.newInstance(uar)
                showDialogInner(confirmationDialog)
                showUninstallationDialog()
            }

            UninstallStage.STAGE_FAILED -> {
@@ -153,15 +149,42 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener {
        }
    }

    private fun showUninstallationDialog() {
        val fragment = getUninstallationFragment() ?: UninstallationFragment()
        fragment.updateUI()
        showDialogInner(fragment, TAG_UNINSTALLATION_DIALOG)
    }

    /**
     * Replace any visible dialog by the dialog returned by InstallRepository
     * Replace any visible dialog by the dialog returned by UninstallRepository with the tag
     * TAG_DIALOG.
     *
     * @param newDialog The new dialog to display
     */
    private fun showDialogInner(newDialog: DialogFragment?) {
        val currentDialog = fragmentManager!!.findFragmentByTag(TAG_DIALOG) as DialogFragment?
        currentDialog?.dismissAllowingStateLoss()
        newDialog?.show(fragmentManager!!, TAG_DIALOG)
        showDialogInner(newDialog, TAG_DIALOG)
    }
    private fun showDialogInner(newDialog: DialogFragment?, tag: String) {
        var currentTag: String? = null
        if (tag == TAG_UNINSTALLATION_DIALOG) {
            if (getUninstallationFragment() != null) {
                return
            }
            currentTag = TAG_DIALOG
        } else {
            currentTag = TAG_UNINSTALLATION_DIALOG
        }

        val currentDialog = fragmentManager!!.findFragmentByTag(currentTag)
        if (currentDialog is DialogFragment) {
            currentDialog.dismissAllowingStateLoss()
        }
        newDialog?.show(fragmentManager!!, tag)
    }

    private fun getUninstallationFragment(): UninstallationFragment? {
        return (fragmentManager!!.findFragmentByTag(TAG_UNINSTALLATION_DIALOG)
            ?: return null) as UninstallationFragment?
    }

    fun setResult(resultCode: Int, data: Intent?, shouldFinish: Boolean) {
+0 −136
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.packageinstaller.v2.ui.fragments;

import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_SNIPPET;
import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_INSTALLER_LABEL;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;

import com.android.packageinstaller.R;
import com.android.packageinstaller.v2.model.PackageUtil;
import com.android.packageinstaller.v2.model.UnarchiveUserActionRequired;
import com.android.packageinstaller.v2.ui.UiUtil;
import com.android.packageinstaller.v2.ui.UnarchiveActionListener;

public class UnarchiveConfirmationFragment extends DialogFragment {

    private static final String LOG_TAG = UnarchiveConfirmationFragment.class.getSimpleName();

    private Dialog mDialog;
    private UnarchiveUserActionRequired mDialogData;
    private UnarchiveActionListener mUnarchiveActionListener;

    UnarchiveConfirmationFragment() {
        // Required for DialogFragment
    }

    /**
     * Creates a new instance of this fragment with necessary data set as fragment arguments
     *
     * @param dialogData {@link UnarchiveUserActionRequired} object containing data to display
     *         in the dialog
     * @return an instance of the fragment
     */
    public static UnarchiveConfirmationFragment newInstance(
            @NonNull UnarchiveUserActionRequired dialogData) {
        Bundle args = new Bundle();
        args.putParcelable(ARGS_APP_SNIPPET, dialogData.getAppSnippet());
        args.putString(ARGS_INSTALLER_LABEL, dialogData.getInstallerTitle());

        UnarchiveConfirmationFragment dialog = new UnarchiveConfirmationFragment();
        dialog.setArguments(args);
        return dialog;
    }

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

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        setDialogData(requireArguments());

        Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData);

        // There is no root view here. Ok to pass null view root
        @SuppressWarnings("InflateParams")
        View dialogView = getLayoutInflater().inflate(R.layout.uninstall_fragment_layout, null);
        dialogView.requireViewById(R.id.app_snippet).setVisibility(View.VISIBLE);
        ((ImageView) dialogView.requireViewById(R.id.app_icon))
            .setImageDrawable(mDialogData.getAppIcon());
        ((TextView) dialogView.requireViewById(R.id.app_label)).setText(mDialogData.getAppLabel());

        TextView customMessage = dialogView.requireViewById(R.id.custom_message);
        customMessage.setVisibility(View.VISIBLE);
        customMessage.setText(getString(R.string.message_restore, mDialogData.getInstallerTitle()));

        mDialog = UiUtil.getAlertDialog(requireContext(), getString(R.string.title_restore),
                dialogView, R.string.button_restore, R.string.button_cancel,
                (dialog, which) -> mUnarchiveActionListener.beginUnarchive(),
                (dialog, which) -> {});
        return mDialog;
    }

    @Override
    public void onPause() {
        super.onPause();
        Button button = UiUtil.getAlertDialogPositiveButton(mDialog);
        if (button != null) {
            button.setEnabled(false);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        Button button = UiUtil.getAlertDialogPositiveButton(mDialog);
        if (button != null) {
            button.setEnabled(true);
        }
    }

    @Override
    public void onDismiss(@NonNull DialogInterface dialog) {
        super.onDismiss(dialog);
        if (isAdded()) {
            requireActivity().finish();
        }
    }

    private void setDialogData(Bundle args) {
        PackageUtil.AppSnippet appSnippet = args.getParcelable(ARGS_APP_SNIPPET,
                PackageUtil.AppSnippet.class);
        String installerTitle = args.getString(ARGS_INSTALLER_LABEL);

        mDialogData = new UnarchiveUserActionRequired(appSnippet, installerTitle);
    }
}
+274 −0

File changed and moved.

Preview size limit exceeded, changes collapsed.

Loading