1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.packageinstaller.v2.model
18 
19 import android.app.Activity
20 import android.content.Intent
21 import android.content.pm.PackageManager
22 import android.content.pm.PackageInstaller
23 import android.graphics.drawable.Drawable
24 
25 sealed class InstallStage(val stageCode: Int) {
26 
27     companion object {
28         const val STAGE_DEFAULT = -1
29         const val STAGE_ABORTED = 0
30         const val STAGE_STAGING = 1
31         const val STAGE_READY = 2
32         const val STAGE_USER_ACTION_REQUIRED = 3
33         const val STAGE_INSTALLING = 4
34         const val STAGE_SUCCESS = 5
35         const val STAGE_FAILED = 6
36     }
37 }
38 
39 class InstallStaging : InstallStage(STAGE_STAGING)
40 
41 class InstallReady : InstallStage(STAGE_READY)
42 
43 data class InstallUserActionRequired(
44     val actionReason: Int,
45     private val appSnippet: PackageUtil.AppSnippet? = null,
46     val isAppUpdating: Boolean = false,
47     /**
48      * This holds either a package name or the app label of the install source.
49      */
50     val sourceApp: String? = null,
51 ) : InstallStage(STAGE_USER_ACTION_REQUIRED) {
52 
53     val appIcon: Drawable?
54         get() = appSnippet?.icon
55 
56     val appLabel: String?
<lambda>null57         get() = appSnippet?.let { appSnippet.label as String? }
58 
59     companion object {
60         const val USER_ACTION_REASON_UNKNOWN_SOURCE = 0
61         const val USER_ACTION_REASON_ANONYMOUS_SOURCE = 1
62         const val USER_ACTION_REASON_INSTALL_CONFIRMATION = 2
63     }
64 }
65 
66 data class InstallInstalling(private val appSnippet: PackageUtil.AppSnippet) :
67     InstallStage(STAGE_INSTALLING) {
68 
69     val appIcon: Drawable?
70         get() = appSnippet.icon
71 
72     val appLabel: String?
73         get() = appSnippet.label as String?
74 }
75 
76 data class InstallSuccess(
77     private val appSnippet: PackageUtil.AppSnippet,
78     val shouldReturnResult: Boolean = false,
79     /**
80      *
81      * * If the caller is requesting a result back, this will hold an Intent with
82      * [Intent.EXTRA_INSTALL_RESULT] set to [PackageManager.INSTALL_SUCCEEDED].
83      *
84      * * If the caller doesn't want the result back, this will hold an Intent that launches
85      * the newly installed / updated app if a launchable activity exists.
86      */
87     val resultIntent: Intent? = null,
88 ) : InstallStage(STAGE_SUCCESS) {
89 
90     val appIcon: Drawable?
91         get() = appSnippet.icon
92 
93     val appLabel: String?
94         get() = appSnippet.label as String?
95 }
96 
97 data class InstallFailed(
98     private val appSnippet: PackageUtil.AppSnippet? = null,
99     val legacyCode: Int,
100     val statusCode: Int,
101     val message: String? = null,
102     val shouldReturnResult: Boolean = false,
103     /**
104      * If the caller is requesting a result back, this will hold an Intent with
105      * [Intent.EXTRA_INSTALL_RESULT] set to the [PackageInstaller.EXTRA_LEGACY_STATUS].
106      */
107     val resultIntent: Intent? = null
108 ) : InstallStage(STAGE_FAILED) {
109 
110     val appIcon: Drawable?
111         get() = appSnippet?.icon
112 
113     val appLabel: String?
114         get() = appSnippet?.label as String?
115 }
116 
117 data class InstallAborted(
118     val abortReason: Int,
119     /**
120      * It will hold the restriction name, when the restriction was enforced by the system, and not
121      * a device admin.
122      */
123     val message: String? = null,
124     /**
125      * * If abort reason is [ABORT_REASON_POLICY], then this will hold the Intent
126      * to display a support dialog when a feature was disabled by an admin. It will be
127      * `null` if the feature is disabled by the system. In this case, the restriction name
128      * will be set in [message]
129      * * If the abort reason is [ABORT_REASON_INTERNAL_ERROR], it **may** hold an
130      * intent to be sent as a result to the calling activity.
131      */
132     val resultIntent: Intent? = null,
133     val activityResultCode: Int = Activity.RESULT_CANCELED,
134     val errorDialogType: Int? = DLG_NONE,
135 ) : InstallStage(STAGE_ABORTED) {
136 
137     companion object {
138         const val ABORT_REASON_INTERNAL_ERROR = 0
139         const val ABORT_REASON_POLICY = 1
140         const val ABORT_REASON_DONE = 2
141         const val DLG_NONE = 0
142         const val DLG_PACKAGE_ERROR = 1
143     }
144 }
145