1 /* 2 * Copyright (C) 2017 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.launcher3.util; 18 19 import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_HOME_ROLE; 20 21 import android.app.ActivityOptions; 22 import android.app.Person; 23 import android.app.role.RoleManager; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.LauncherActivityInfo; 28 import android.content.pm.ShortcutInfo; 29 import android.graphics.drawable.ColorDrawable; 30 import android.net.Uri; 31 import android.os.Process; 32 import android.os.UserHandle; 33 import android.os.UserManager; 34 import android.util.ArrayMap; 35 36 import androidx.annotation.NonNull; 37 import androidx.annotation.Nullable; 38 39 import com.android.launcher3.BuildConfig; 40 import com.android.launcher3.Launcher; 41 import com.android.launcher3.Utilities; 42 import com.android.launcher3.dagger.ApplicationContext; 43 import com.android.launcher3.dagger.LauncherAppComponent; 44 import com.android.launcher3.dagger.LauncherAppSingleton; 45 46 import java.util.Collections; 47 import java.util.List; 48 import java.util.Map; 49 50 import javax.inject.Inject; 51 52 /** 53 * A wrapper for the hidden API calls 54 */ 55 @LauncherAppSingleton 56 public class ApiWrapper { 57 58 public static final DaggerSingletonObject<ApiWrapper> INSTANCE = new DaggerSingletonObject<>( 59 LauncherAppComponent::getApiWrapper); 60 61 protected final Context mContext; 62 private final String[] mLegacyMultiInstanceSupportedApps; 63 64 @Inject ApiWrapper(@pplicationContext Context context)65 public ApiWrapper(@ApplicationContext Context context) { 66 mContext = context; 67 mLegacyMultiInstanceSupportedApps = context.getResources().getStringArray( 68 com.android.launcher3.R.array.config_appsSupportMultiInstancesSplit); 69 } 70 71 /** 72 * Returns the list of persons associated with the provided shortcut info 73 */ getPersons(ShortcutInfo si)74 public Person[] getPersons(ShortcutInfo si) { 75 return Utilities.EMPTY_PERSON_ARRAY; 76 } 77 getActivityOverrides()78 public Map<String, LauncherActivityInfo> getActivityOverrides() { 79 return Collections.emptyMap(); 80 } 81 82 /** 83 * Creates an ActivityOptions to play fade-out animation on closing targets 84 */ createFadeOutAnimOptions()85 public ActivityOptions createFadeOutAnimOptions() { 86 return ActivityOptions.makeCustomAnimation(mContext, 0, android.R.anim.fade_out); 87 } 88 89 /** 90 * Returns a map of all users on the device to their corresponding UI properties 91 */ queryAllUsers()92 public Map<UserHandle, UserIconInfo> queryAllUsers() { 93 UserManager um = mContext.getSystemService(UserManager.class); 94 Map<UserHandle, UserIconInfo> users = new ArrayMap<>(); 95 List<UserHandle> usersActual = um.getUserProfiles(); 96 if (usersActual != null) { 97 for (UserHandle user : usersActual) { 98 long serial = um.getSerialNumberForUser(user); 99 100 // Simple check to check if the provided user is work profile 101 // TODO: Migrate to a better platform API 102 NoopDrawable d = new NoopDrawable(); 103 boolean isWork = (d != mContext.getPackageManager().getUserBadgedIcon(d, user)); 104 UserIconInfo info = new UserIconInfo( 105 user, 106 isWork ? UserIconInfo.TYPE_WORK : UserIconInfo.TYPE_MAIN, 107 serial); 108 users.put(user, info); 109 } 110 } 111 return users; 112 } 113 114 /** 115 * Returns the list of the system packages that are installed at user creation. 116 * An empty list denotes that all system packages are installed for that user at creation. 117 */ getPreInstalledSystemPackages(UserHandle user)118 public List<String> getPreInstalledSystemPackages(UserHandle user) { 119 return Collections.emptyList(); 120 } 121 122 /** 123 * Returns an intent which can be used to start the App Market activity (Installer 124 * Activity). 125 */ getAppMarketActivityIntent(String packageName, UserHandle user)126 public Intent getAppMarketActivityIntent(String packageName, UserHandle user) { 127 return createMarketIntent(packageName); 128 } 129 130 /** 131 * Returns an intent which can be used to start a search for a package on app market 132 */ getMarketSearchIntent(String packageName, UserHandle user)133 public Intent getMarketSearchIntent(String packageName, UserHandle user) { 134 // If we are search for the current user, just launch the market directly as the 135 // system won't have the installer details either 136 return (Process.myUserHandle().equals(user)) 137 ? createMarketIntent(packageName) 138 : getAppMarketActivityIntent(packageName, user); 139 } 140 createMarketIntent(String packageName)141 private static Intent createMarketIntent(String packageName) { 142 return new Intent(Intent.ACTION_VIEW) 143 .setData(new Uri.Builder() 144 .scheme("market") 145 .authority("details") 146 .appendQueryParameter("id", packageName) 147 .build()) 148 .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app") 149 .authority(BuildConfig.APPLICATION_ID).build()); 150 } 151 152 /** 153 * Returns an intent which can be used to open Private Space Settings. 154 */ 155 @Nullable getPrivateSpaceSettingsIntent()156 public Intent getPrivateSpaceSettingsIntent() { 157 return null; 158 } 159 160 /** 161 * Checks if an activity is flagged as non-resizeable. 162 */ isNonResizeableActivity(@onNull LauncherActivityInfo lai)163 public boolean isNonResizeableActivity(@NonNull LauncherActivityInfo lai) { 164 // Overridden in Quickstep 165 return false; 166 } 167 168 /** 169 * Checks if an activity supports multi-instance. 170 */ supportsMultiInstance(@onNull LauncherActivityInfo lai)171 public boolean supportsMultiInstance(@NonNull LauncherActivityInfo lai) { 172 // Check app multi-instance properties after V 173 if (!Utilities.ATLEAST_V) { 174 return false; 175 } 176 177 // Check the legacy hardcoded allowlist first 178 for (String pkg : mLegacyMultiInstanceSupportedApps) { 179 if (pkg.equals(lai.getComponentName().getPackageName())) { 180 return true; 181 } 182 } 183 184 // Overridden in Quickstep 185 return false; 186 } 187 /** 188 * Starts an Activity which can be used to set this Launcher as the HOME app, via a consent 189 * screen. In case the consent screen cannot be shown, or the user does not set current Launcher 190 * as HOME app, a toast asking the user to do the latter is shown. 191 */ assignDefaultHomeRole(Context context)192 public void assignDefaultHomeRole(Context context) { 193 RoleManager roleManager = context.getSystemService(RoleManager.class); 194 assert roleManager != null; 195 if (roleManager.isRoleAvailable(RoleManager.ROLE_HOME) 196 && !roleManager.isRoleHeld(RoleManager.ROLE_HOME)) { 197 Intent roleRequestIntent = roleManager.createRequestRoleIntent( 198 RoleManager.ROLE_HOME); 199 Launcher launcher = Launcher.getLauncher(context); 200 launcher.startActivityForResult(roleRequestIntent, REQUEST_HOME_ROLE); 201 } 202 } 203 204 /** 205 * Returns a hash to uniquely identify a particular version of appInfo 206 */ getApplicationInfoHash(@onNull ApplicationInfo appInfo)207 public String getApplicationInfoHash(@NonNull ApplicationInfo appInfo) { 208 // The hashString in source dir changes with every install 209 return appInfo.sourceDir; 210 } 211 212 /** 213 * Returns the round icon resource Id if defined by the app 214 */ getRoundIconRes(@onNull ApplicationInfo appInfo)215 public int getRoundIconRes(@NonNull ApplicationInfo appInfo) { 216 return 0; 217 } 218 219 /** 220 * Checks if the shortcut is using an icon with file or URI source 221 */ isFileDrawable(@onNull ShortcutInfo shortcutInfo)222 public boolean isFileDrawable(@NonNull ShortcutInfo shortcutInfo) { 223 return false; 224 } 225 226 private static class NoopDrawable extends ColorDrawable { 227 @Override getIntrinsicHeight()228 public int getIntrinsicHeight() { 229 return 1; 230 } 231 232 @Override getIntrinsicWidth()233 public int getIntrinsicWidth() { 234 return 1; 235 } 236 } 237 } 238