1 /*
2  * Copyright (C) 2022 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  *      http://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.internal.app;
18 
19 import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_PERSONAL_APPS;
20 import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_WORK_APPS;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.app.admin.DevicePolicyEventLogger;
25 import android.app.admin.DevicePolicyManager;
26 import android.content.Context;
27 import android.content.pm.ResolveInfo;
28 import android.os.UserHandle;
29 import android.stats.devicepolicy.nano.DevicePolicyEnums;
30 
31 import com.android.internal.R;
32 import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyState;
33 import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider;
34 
35 import java.util.List;
36 
37 /**
38  * Chooser/ResolverActivity empty state provider that returns empty state which is shown when
39  * there are no apps available.
40  */
41 public class NoAppsAvailableEmptyStateProvider implements EmptyStateProvider {
42 
43     @NonNull
44     private final Context mContext;
45     @Nullable
46     private final UserHandle mWorkProfileUserHandle;
47     @Nullable
48     private final UserHandle mPersonalProfileUserHandle;
49     @NonNull
50     private final String mMetricsCategory;
51     @NonNull
52     private final UserHandle mTabOwnerUserHandleForLaunch;
53 
NoAppsAvailableEmptyStateProvider(Context context, UserHandle workProfileUserHandle, UserHandle personalProfileUserHandle, String metricsCategory, UserHandle tabOwnerUserHandleForLaunch)54     public NoAppsAvailableEmptyStateProvider(Context context, UserHandle workProfileUserHandle,
55             UserHandle personalProfileUserHandle, String metricsCategory,
56             UserHandle tabOwnerUserHandleForLaunch) {
57         mContext = context;
58         mWorkProfileUserHandle = workProfileUserHandle;
59         mPersonalProfileUserHandle = personalProfileUserHandle;
60         mMetricsCategory = metricsCategory;
61         mTabOwnerUserHandleForLaunch = tabOwnerUserHandleForLaunch;
62     }
63 
64     @Nullable
65     @Override
66     @SuppressWarnings("ReferenceEquality")
getEmptyState(ResolverListAdapter resolverListAdapter)67     public EmptyState getEmptyState(ResolverListAdapter resolverListAdapter) {
68         UserHandle listUserHandle = resolverListAdapter.getUserHandle();
69 
70         if (mWorkProfileUserHandle != null
71                 && (mTabOwnerUserHandleForLaunch.equals(listUserHandle)
72                 || !hasAppsInOtherProfile(resolverListAdapter))) {
73 
74             String title;
75             if (listUserHandle == mPersonalProfileUserHandle) {
76                 title = mContext.getSystemService(
77                         DevicePolicyManager.class).getResources().getString(
78                         RESOLVER_NO_PERSONAL_APPS,
79                         () -> mContext.getString(R.string.resolver_no_personal_apps_available));
80             } else {
81                 title = mContext.getSystemService(
82                         DevicePolicyManager.class).getResources().getString(
83                         RESOLVER_NO_WORK_APPS,
84                         () -> mContext.getString(R.string.resolver_no_work_apps_available));
85             }
86 
87             return new NoAppsAvailableEmptyState(
88                     title, mMetricsCategory,
89                     /* isPersonalProfile= */ listUserHandle == mPersonalProfileUserHandle
90             );
91         } else if (mWorkProfileUserHandle == null) {
92             // Return default empty state without tracking
93             return new DefaultEmptyState();
94         }
95 
96         return null;
97     }
98 
hasAppsInOtherProfile(ResolverListAdapter adapter)99     private boolean hasAppsInOtherProfile(ResolverListAdapter adapter) {
100         if (mWorkProfileUserHandle == null) {
101             return false;
102         }
103         List<ResolverActivity.ResolvedComponentInfo> resolversForIntent =
104                 adapter.getResolversForUser(mTabOwnerUserHandleForLaunch);
105         for (ResolverActivity.ResolvedComponentInfo info : resolversForIntent) {
106             ResolveInfo resolveInfo = info.getResolveInfoAt(0);
107             if (resolveInfo.targetUserId != UserHandle.USER_CURRENT) {
108                 return true;
109             }
110         }
111         return false;
112     }
113 
114     public static class DefaultEmptyState implements EmptyState {
115         @Override
useDefaultEmptyView()116         public boolean useDefaultEmptyView() {
117             return true;
118         }
119     }
120 
121     public static class NoAppsAvailableEmptyState implements EmptyState {
122 
123         @NonNull
124         private String mTitle;
125 
126         @NonNull
127         private String mMetricsCategory;
128 
129         private boolean mIsPersonalProfile;
130 
NoAppsAvailableEmptyState(String title, String metricsCategory, boolean isPersonalProfile)131         public NoAppsAvailableEmptyState(String title, String metricsCategory,
132                 boolean isPersonalProfile) {
133             mTitle = title;
134             mMetricsCategory = metricsCategory;
135             mIsPersonalProfile = isPersonalProfile;
136         }
137 
138         @Nullable
139         @Override
getTitle()140         public String getTitle() {
141             return mTitle;
142         }
143 
144         @Override
onEmptyStateShown()145         public void onEmptyStateShown() {
146             DevicePolicyEventLogger.createEvent(
147                             DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_APPS_RESOLVED)
148                     .setStrings(mMetricsCategory)
149                     .setBoolean(/*isPersonalProfile*/ mIsPersonalProfile)
150                     .write();
151         }
152     }
153 }