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.graphics.drawable.Drawable
23 
24 sealed class InstallStage(val stageCode: Int) {
25 
26     companion object {
27         const val STAGE_DEFAULT = -1
28         const val STAGE_ABORTED = 0
29         const val STAGE_STAGING = 1
30         const val STAGE_READY = 2
31         const val STAGE_USER_ACTION_REQUIRED = 3
32         const val STAGE_INSTALLING = 4
33         const val STAGE_SUCCESS = 5
34         const val STAGE_FAILED = 6
35     }
36 }
37 
38 class InstallStaging : InstallStage(STAGE_STAGING)
39 
40 class InstallReady : InstallStage(STAGE_READY)
41 
42 data class InstallUserActionRequired(
43     val actionReason: Int,
44     private val appSnippet: PackageUtil.AppSnippet? = null,
45     val isAppUpdating: Boolean = false,
46     val dialogMessage: String? = null,
47 ) : InstallStage(STAGE_USER_ACTION_REQUIRED) {
48 
49     val appIcon: Drawable?
50         get() = appSnippet?.icon
51 
52     val appLabel: String?
<lambda>null53         get() = appSnippet?.let { appSnippet.label as String? }
54 
55     companion object {
56         const val USER_ACTION_REASON_UNKNOWN_SOURCE = 0
57         const val USER_ACTION_REASON_ANONYMOUS_SOURCE = 1
58         const val USER_ACTION_REASON_INSTALL_CONFIRMATION = 2
59     }
60 }
61 
62 data class InstallInstalling(private val appSnippet: PackageUtil.AppSnippet) :
63     InstallStage(STAGE_INSTALLING) {
64 
65     val appIcon: Drawable?
66         get() = appSnippet.icon
67 
68     val appLabel: String?
69         get() = appSnippet.label as String?
70 }
71 
72 data class InstallSuccess(
73     private val appSnippet: PackageUtil.AppSnippet,
74     val shouldReturnResult: Boolean = false,
75     /**
76      *
77      * * If the caller is requesting a result back, this will hold the Intent with
78      * [Intent.EXTRA_INSTALL_RESULT] set to [PackageManager.INSTALL_SUCCEEDED] which is sent
79      * back to the caller.
80      *
81      * * If the caller doesn't want the result back, this will hold the Intent that launches
82      * the newly installed / updated app if a launchable activity exists.
83      */
84     val resultIntent: Intent? = null,
85 ) : InstallStage(STAGE_SUCCESS) {
86 
87     val appIcon: Drawable?
88         get() = appSnippet.icon
89 
90     val appLabel: String?
91         get() = appSnippet.label as String?
92 }
93 
94 data class InstallFailed(
95     private val appSnippet: PackageUtil.AppSnippet,
96     val legacyCode: Int,
97     val statusCode: Int,
98     val message: String?,
99 ) : InstallStage(STAGE_FAILED) {
100 
101     val appIcon: Drawable?
102         get() = appSnippet.icon
103 
104     val appLabel: String?
105         get() = appSnippet.label as String?
106 }
107 
108 data class InstallAborted(
109     val abortReason: Int,
110     /**
111      * It will hold the restriction name, when the restriction was enforced by the system, and not
112      * a device admin.
113      */
114     val message: String? = null,
115     /**
116      * * If abort reason is [ABORT_REASON_POLICY], then this will hold the Intent
117      * to display a support dialog when a feature was disabled by an admin. It will be
118      * `null` if the feature is disabled by the system. In this case, the restriction name
119      * will be set in [message]
120      * * If the abort reason is [ABORT_REASON_INTERNAL_ERROR], it **may** hold an
121      * intent to be sent as a result to the calling activity.
122      */
123     val resultIntent: Intent? = null,
124     val activityResultCode: Int = Activity.RESULT_CANCELED,
125     val errorDialogType: Int? = DLG_NONE,
126 ) : InstallStage(STAGE_ABORTED) {
127 
128     companion object {
129         const val ABORT_REASON_INTERNAL_ERROR = 0
130         const val ABORT_REASON_POLICY = 1
131         const val ABORT_REASON_DONE = 2
132         const val DLG_NONE = 0
133         const val DLG_PACKAGE_ERROR = 1
134     }
135 }
136