1 /* 2 * Copyright (C) 2021 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.companiondevicemanager; 18 19 import android.annotation.NonNull; 20 import android.annotation.StringRes; 21 import android.content.Context; 22 import android.content.pm.ApplicationInfo; 23 import android.content.pm.PackageManager; 24 import android.content.pm.PackageManager.ApplicationInfoFlags; 25 import android.content.res.Configuration; 26 import android.graphics.drawable.Drawable; 27 import android.os.Bundle; 28 import android.os.Handler; 29 import android.os.Looper; 30 import android.os.Parcel; 31 import android.os.ResultReceiver; 32 import android.text.Html; 33 import android.text.Spanned; 34 35 /** 36 * Utilities. 37 */ 38 class Utils { 39 private static final String COMPANION_DEVICE_ACTIVITY_VENDOR_ICON = 40 "android.companion.vendor_icon"; 41 private static final String COMPANION_DEVICE_ACTIVITY_VENDOR_NAME = 42 "android.companion.vendor_name"; 43 44 /** 45 * Convert an instance of a "locally-defined" ResultReceiver to an instance of 46 * {@link android.os.ResultReceiver} itself, which the receiving process will be able to 47 * unmarshall. 48 */ prepareResultReceiverForIpc(T resultReceiver)49 static <T extends ResultReceiver> ResultReceiver prepareResultReceiverForIpc(T resultReceiver) { 50 final Parcel parcel = Parcel.obtain(); 51 resultReceiver.writeToParcel(parcel, 0); 52 parcel.setDataPosition(0); 53 54 final ResultReceiver ipcFriendly = ResultReceiver.CREATOR.createFromParcel(parcel); 55 parcel.recycle(); 56 57 return ipcFriendly; 58 } 59 getApplicationLabel( @onNull Context context, @NonNull String packageName, int userId)60 static @NonNull CharSequence getApplicationLabel( 61 @NonNull Context context, @NonNull String packageName, int userId) 62 throws PackageManager.NameNotFoundException { 63 final PackageManager packageManager = context.getPackageManager(); 64 65 final ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser( 66 packageName, PackageManager.ApplicationInfoFlags.of(0), userId); 67 68 return packageManager.getApplicationLabel(appInfo); 69 } 70 getApplicationIcon(@onNull Context context, @NonNull String packageName)71 static @NonNull Drawable getApplicationIcon(@NonNull Context context, 72 @NonNull String packageName) throws PackageManager.NameNotFoundException { 73 final PackageManager packageManager = context.getPackageManager(); 74 return packageManager.getApplicationIcon(packageName); 75 } 76 getHtmlFromResources( @onNull Context context, @StringRes int resId, CharSequence... formatArgs)77 static Spanned getHtmlFromResources( 78 @NonNull Context context, @StringRes int resId, CharSequence... formatArgs) { 79 final String[] escapedArgs = new String[formatArgs.length]; 80 for (int i = 0; i < escapedArgs.length; i++) { 81 escapedArgs[i] = Html.escapeHtml(formatArgs[i]); 82 } 83 final String plain = context.getString(resId, (Object[]) escapedArgs); 84 return Html.fromHtml(plain, 0); 85 } 86 getVendorHeaderIcon(@onNull Context context, @NonNull String packageName, int userId)87 static @NonNull Drawable getVendorHeaderIcon(@NonNull Context context, 88 @NonNull String packageName, int userId) throws PackageManager.NameNotFoundException { 89 final ApplicationInfo appInfo = getApplicationInfo(context, packageName, userId); 90 final Bundle bundle = appInfo.metaData; 91 int resId = bundle == null ? 0 : bundle.getInt(COMPANION_DEVICE_ACTIVITY_VENDOR_ICON, 0); 92 93 if (bundle == null || resId == 0) { 94 return getApplicationIcon(context, packageName); 95 } 96 97 return context.createPackageContext(packageName, /* flags= */ 0).getDrawable(resId); 98 } 99 getVendorHeaderName(@onNull Context context, @NonNull String packageName, int userId)100 static CharSequence getVendorHeaderName(@NonNull Context context, 101 @NonNull String packageName, int userId) throws PackageManager.NameNotFoundException { 102 final ApplicationInfo appInfo = getApplicationInfo(context, packageName, userId); 103 final Bundle bundle = appInfo.metaData; 104 105 if (bundle == null) { 106 return ""; 107 } 108 109 return appInfo.metaData.getCharSequence(COMPANION_DEVICE_ACTIVITY_VENDOR_NAME, ""); 110 } 111 hasVendorIcon(@onNull Context context, @NonNull String packageName, int userId)112 static boolean hasVendorIcon(@NonNull Context context, 113 @NonNull String packageName, int userId) throws PackageManager.NameNotFoundException { 114 final ApplicationInfo appInfo = getApplicationInfo(context, packageName, userId); 115 final Bundle bundle = appInfo.metaData; 116 117 if (bundle == null) { 118 return false; 119 } else { 120 return bundle.getInt(COMPANION_DEVICE_ACTIVITY_VENDOR_ICON) != 0; 121 } 122 } 123 isDarkTheme(@onNull Context context)124 private static boolean isDarkTheme(@NonNull Context context) { 125 int nightModeFlags = context.getResources().getConfiguration().uiMode 126 & Configuration.UI_MODE_NIGHT_MASK; 127 return nightModeFlags == Configuration.UI_MODE_NIGHT_YES; 128 } 129 130 // Get image color for the corresponding theme. getImageColor(@onNull Context context)131 static int getImageColor(@NonNull Context context) { 132 if (isDarkTheme(context)) { 133 return android.R.color.system_accent1_200; 134 } else { 135 return android.R.color.system_accent1_600; 136 } 137 } 138 /** 139 * Getting ApplicationInfo from meta-data. 140 */ getApplicationInfo(@onNull Context context, @NonNull String packageName, int userId)141 private static @NonNull ApplicationInfo getApplicationInfo(@NonNull Context context, 142 @NonNull String packageName, int userId) throws PackageManager.NameNotFoundException { 143 final PackageManager packageManager = context.getPackageManager(); 144 final ApplicationInfoFlags flags = ApplicationInfoFlags.of(PackageManager.GET_META_DATA); 145 final ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser( 146 packageName, flags, userId); 147 148 return appInfo; 149 } 150 getIcon(@onNull Context context, int resId)151 static @NonNull Drawable getIcon(@NonNull Context context, int resId) { 152 Drawable icon = context.getResources().getDrawable(resId, null); 153 return icon; 154 } 155 runOnMainThread(Runnable runnable)156 static void runOnMainThread(Runnable runnable) { 157 if (Thread.currentThread() == Looper.getMainLooper().getThread()) { 158 runnable.run(); 159 } else { 160 Handler.getMain().post(runnable); 161 } 162 } 163 Utils()164 private Utils() { 165 } 166 } 167