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

Commit 09d0c763 authored by Ivan Chiang's avatar Ivan Chiang
Browse files

[PM] Support better transition in PIA V2 (1/N)

- Migrate installation fragments to one new InstallationFragment
  except Failed and error fragments

Flag: android.content.pm.use_pia_v2
Test: atest CtsPackageInstallerCUJInstallationTestCases
Test: atest CtsPackageInstallerCUJUpdateOwnerShipTestCases
Bug: 274120822
Bug: 402448072
Change-Id: I64c4d797ed3d453c71fb1a2317fdf2e974d78d7b
parent 52bdf8e9
Loading
Loading
Loading
Loading
+0 −31
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?><!--
  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.
  -->

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:paddingHorizontal="?android:attr/dialogPreferredPadding"
    android:paddingBottom="@dimen/alert_dialog_inner_padding"
    android:paddingTop="@dimen/alert_dialog_inner_padding">

    <TextView
        style="?attr/textAppearanceInstallerCustomMessage"
        android:id="@+id/custom_message"
        android:layout_height="wrap_content"
        android:layout_width="match_parent" />

</ScrollView>
+2 −2
Original line number Diff line number Diff line
@@ -56,6 +56,6 @@
    <!-- 24dp + 364dp + 24dp for the portrait mode -->
    <dimen name="alert_dialog_min_width_minor">412dp</dimen>
    <!-- Override the values for the buttonbar paddings in M3 MaterialAlertDialog -->
    <dimen name="m3_alert_dialog_action_top_padding">0dp</dimen>
    <dimen name="m3_alert_dialog_action_bottom_padding">8dp</dimen>
    <dimen name="m3_alert_dialog_action_top_padding">4dp</dimen>
    <dimen name="m3_alert_dialog_action_bottom_padding">20dp</dimen>
</resources>
+6 −6
Original line number Diff line number Diff line
@@ -69,7 +69,6 @@

    <!-- Material design -->
    <style name="Widget.PackageInstaller.Material.ButtonBar" parent="">
        <item name="android:paddingBottom">16dp</item>
        <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Widget.Button</item>
    </style>

@@ -80,7 +79,8 @@
    </style>

    <style name="Widget.PackageInstaller.Material.Button" parent="@style/Widget.Material3.Button.TextButton.Dialog">
        <item name="android:insetTop">8dp</item>
        <item name="android:insetBottom">4dp</item>
        <item name="android:insetTop">4dp</item>
        <item name="android:layout_marginStart">8dp</item>
        <item name="android:minHeight">@dimen/button_min_height</item>
        <item name="android:textAppearance">@style/TextAppearance.PackageInstaller.LabelLarge</item>
@@ -88,8 +88,8 @@
    </style>

    <style name="Widget.PackageInstaller.Material.Button.Colored" parent="@style/Widget.Material3.Button">
        <item name="android:insetBottom">0dp</item>
        <item name="android:insetTop">8dp</item>
        <item name="android:insetBottom">4dp</item>
        <item name="android:insetTop">4dp</item>
        <item name="android:layout_marginStart">8dp</item>
        <item name="android:minHeight">@dimen/button_min_height</item>
        <item name="android:paddingHorizontal">16dp</item>
@@ -99,8 +99,8 @@
    </style>

    <style name="Widget.PackageInstaller.Material.Button.Outlined" parent="@style/Widget.Material3.Button.OutlinedButton">
        <item name="android:insetBottom">0dp</item>
        <item name="android:insetTop">8dp</item>
        <item name="android:insetBottom">4dp</item>
        <item name="android:insetTop">4dp</item>
        <item name="android:layout_marginStart">8dp</item>
        <item name="android:minHeight">@dimen/button_min_height</item>
        <item name="android:paddingHorizontal">16dp</item>
+0 −5
Original line number Diff line number Diff line
@@ -59,11 +59,6 @@
        <item name="shapeAppearanceOverlay">@style/ShapeAppearance</item>
    </style>

    <style name="Theme.MaterialAlertDialog.Variant" parent="">
        <item name="buttonBarPositiveButtonStyle">@style/Widget.PackageInstaller.Material.Button</item>
        <item name="buttonBarNegativeButtonStyle">@style/Widget.PackageInstaller.Material.Button</item>
    </style>

    <style name="Theme.UninstallerActivity"
        parent="@style/Theme.AlertDialogActivity">
    </style>
+48 −36
Original line number Diff line number Diff line
@@ -37,23 +37,17 @@ import androidx.lifecycle.ViewModelProvider
import com.android.packageinstaller.R
import com.android.packageinstaller.v2.model.InstallAborted
import com.android.packageinstaller.v2.model.InstallFailed
import com.android.packageinstaller.v2.model.InstallInstalling
import com.android.packageinstaller.v2.model.InstallRepository
import com.android.packageinstaller.v2.model.InstallStage
import com.android.packageinstaller.v2.model.InstallSuccess
import com.android.packageinstaller.v2.model.InstallUserActionRequired
import com.android.packageinstaller.v2.model.PackageUtil
import com.android.packageinstaller.v2.model.PackageUtil.localLogv
import com.android.packageinstaller.v2.ui.fragments.AnonymousSourceFragment
import com.android.packageinstaller.v2.ui.fragments.ExternalSourcesBlockedFragment
import com.android.packageinstaller.v2.ui.fragments.InstallConfirmationFragment
import com.android.packageinstaller.v2.ui.fragments.DeveloperVerificationConfirmationFragment
import com.android.packageinstaller.v2.ui.fragments.InstallFailedFragment
import com.android.packageinstaller.v2.ui.fragments.InstallInstallingFragment
import com.android.packageinstaller.v2.ui.fragments.InstallStagingFragment
import com.android.packageinstaller.v2.ui.fragments.InstallSuccessFragment
import com.android.packageinstaller.v2.ui.fragments.ParseErrorFragment
import com.android.packageinstaller.v2.ui.fragments.InstallRestrictionFragment
import com.android.packageinstaller.v2.ui.fragments.DeveloperVerificationConfirmationFragment
import com.android.packageinstaller.v2.ui.fragments.InstallationFragment
import com.android.packageinstaller.v2.ui.fragments.ParseErrorFragment
import com.android.packageinstaller.v2.viewmodel.InstallViewModel
import com.android.packageinstaller.v2.viewmodel.InstallViewModelFactory

@@ -66,6 +60,7 @@ class InstallLaunch : FragmentActivity(), InstallActionListener {
            InstallLaunch::class.java.packageName + ".callingPkgName"
        private val LOG_TAG = InstallLaunch::class.java.simpleName
        private const val TAG_DIALOG = "dialog"
        private const val TAG_INSTALLATION_DIALOG = "installation-dialog"
        private const val ARGS_SAVED_INTENT = "saved_intent"
    }

@@ -132,10 +127,9 @@ class InstallLaunch : FragmentActivity(), InstallActionListener {
    private fun onInstallStageChange(installStage: InstallStage) {
        when (installStage.stageCode) {
            InstallStage.STAGE_STAGING -> {
                val stagingDialog = InstallStagingFragment()
                showDialogInner(stagingDialog)
                showInstallationDialog()
                installViewModel!!.stagingProgress.observe(this) { progress: Int ->
                    stagingDialog.setProgress(progress)
                    getInstallationFragment()?.setProgress(progress)
                }
            }

@@ -161,32 +155,21 @@ class InstallLaunch : FragmentActivity(), InstallActionListener {
            InstallStage.STAGE_USER_ACTION_REQUIRED -> {
                val uar = installStage as InstallUserActionRequired
                when (uar.actionReason) {
                    InstallUserActionRequired.USER_ACTION_REASON_INSTALL_CONFIRMATION -> {
                        val actionDialog = InstallConfirmationFragment.newInstance(uar)
                        showDialogInner(actionDialog)
                    InstallUserActionRequired.USER_ACTION_REASON_ANONYMOUS_SOURCE,
                    InstallUserActionRequired.USER_ACTION_REASON_INSTALL_CONFIRMATION,
                    InstallUserActionRequired.USER_ACTION_REASON_UNKNOWN_SOURCE -> {
                        showInstallationDialog()
                    }

                    InstallUserActionRequired.USER_ACTION_REASON_VERIFICATION_CONFIRMATION -> {
                        val actionDialog = DeveloperVerificationConfirmationFragment(uar)
                        showDialogInner(actionDialog)
                    }

                    InstallUserActionRequired.USER_ACTION_REASON_UNKNOWN_SOURCE -> {
                        val externalSourceDialog = ExternalSourcesBlockedFragment.newInstance(uar)
                        showDialogInner(externalSourceDialog)
                    }

                    InstallUserActionRequired.USER_ACTION_REASON_ANONYMOUS_SOURCE -> {
                        val anonymousSourceDialog = AnonymousSourceFragment()
                        showDialogInner(anonymousSourceDialog)
                    }
                }
            }

            InstallStage.STAGE_INSTALLING -> {
                val installing = installStage as InstallInstalling
                val installingDialog = InstallInstallingFragment.newInstance(installing)
                showDialogInner(installingDialog)
                showInstallationDialog()
            }

            InstallStage.STAGE_SUCCESS -> {
@@ -195,8 +178,7 @@ class InstallLaunch : FragmentActivity(), InstallActionListener {
                    val successIntent = success.resultIntent
                    setResult(RESULT_OK, successIntent, true)
                } else {
                    val successDialog = InstallSuccessFragment.newInstance(success)
                    showDialogInner(successDialog)
                    showInstallationDialog()
                }
            }

@@ -258,25 +240,55 @@ class InstallLaunch : FragmentActivity(), InstallActionListener {
        }
        return when (restriction) {
            UserManager.DISALLOW_INSTALL_APPS ->
                InstallRestrictionFragment.newInstance(R.string.message_no_install_apps_restriction)
                InstallRestrictionFragment.newInstance(
                    R.string.message_no_install_apps_restriction)

            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY ->
                InstallRestrictionFragment.newInstance(R.string.message_no_install_unknown_apps_restriction)
                InstallRestrictionFragment.newInstance(
                    R.string.message_no_install_unknown_apps_restriction)

            else -> null
        }
    }

    private fun showInstallationDialog() {
        val fragment = getInstallationFragment() ?: InstallationFragment()
        fragment.updateUI()
        showDialogInner(fragment, TAG_INSTALLATION_DIALOG)
    }

    /**
     * Replace any visible dialog by the dialog returned by InstallRepository
     * Replace any visible dialog by the dialog returned by InstallRepository 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_INSTALLATION_DIALOG) {
            if (getInstallationFragment() != null) {
                return
            }
            currentTag = TAG_DIALOG
        } else {
            currentTag = TAG_INSTALLATION_DIALOG
        }

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

    private fun getInstallationFragment(): InstallationFragment? {
        return (fragmentManager!!.findFragmentByTag(TAG_INSTALLATION_DIALOG)
            ?: return null) as InstallationFragment?
    }

    fun setResult(resultCode: Int, data: Intent?, shouldFinish: Boolean) {
Loading