1 /* 2 * Copyright (C) 2016 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.server.telecom; 18 19 import android.app.ActivityManager; 20 import android.content.BroadcastReceiver; 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.res.Resources; 26 import android.database.ContentObserver; 27 import android.net.Uri; 28 import android.os.Handler; 29 import android.os.Looper; 30 import android.os.UserHandle; 31 import android.provider.Settings; 32 import android.telecom.DefaultDialerManager; 33 import android.telecom.Log; 34 35 import com.android.internal.annotations.VisibleForTesting; 36 import com.android.internal.util.IndentingPrintWriter; 37 38 import java.util.Objects; 39 import java.util.concurrent.ConcurrentHashMap; 40 import java.util.concurrent.Executor; 41 import java.util.function.IntConsumer; 42 43 public class DefaultDialerCache { 44 private static final String LOG_TAG = "DefaultDialerCache"; 45 @VisibleForTesting 46 public final Handler mHandler = new Handler(Looper.getMainLooper()); 47 private final Context mContext; 48 private final DefaultDialerManagerAdapter mDefaultDialerManagerAdapter; 49 private final ComponentName mSystemDialerComponentName; 50 private final RoleManagerAdapter mRoleManagerAdapter; 51 private final ConcurrentHashMap<Integer, String> mCurrentDefaultDialerPerUser = 52 new ConcurrentHashMap<>(); 53 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 54 @Override 55 public void onReceive(Context context, Intent intent) { 56 mHandler.post(() -> { 57 Log.startSession("DDC.oR"); 58 try { 59 String packageName; 60 if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) { 61 packageName = null; 62 } else if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction()) 63 && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 64 packageName = intent.getData().getSchemeSpecificPart(); 65 } else if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { 66 packageName = null; 67 } else if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { 68 packageName = null; 69 } else { 70 return; 71 } 72 73 refreshCachesForUsersWithPackage(packageName); 74 } finally { 75 Log.endSession(); 76 } 77 }); 78 } 79 }; 80 private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() { 81 @Override 82 public void onReceive(Context context, Intent intent) { 83 if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { 84 int removedUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 85 UserHandle.USER_NULL); 86 if (removedUser == UserHandle.USER_NULL) { 87 Log.w(LOG_TAG, "Expected EXTRA_USER_HANDLE with ACTION_USER_REMOVED"); 88 } else { 89 removeUserFromCache(removedUser); 90 Log.i(LOG_TAG, "Removing user %s", removedUser); 91 } 92 } 93 } 94 }; 95 private final ContentObserver mDefaultDialerObserver = new ContentObserver(mHandler) { 96 @Override 97 public void onChange(boolean selfChange) { 98 Log.startSession("DDC.oC"); 99 try { 100 // We don't get the user ID of the user that changed here, so we'll have to 101 // refresh all of the users. 102 refreshCachesForUsersWithPackage(null); 103 } finally { 104 Log.endSession(); 105 } 106 } 107 108 @Override 109 public boolean deliverSelfNotifications() { 110 return true; 111 } 112 }; 113 private ComponentName mOverrideSystemDialerComponentName; 114 DefaultDialerCache(Context context, DefaultDialerManagerAdapter defaultDialerManagerAdapter, RoleManagerAdapter roleManagerAdapter, TelecomSystem.SyncRoot lock)115 public DefaultDialerCache(Context context, 116 DefaultDialerManagerAdapter defaultDialerManagerAdapter, 117 RoleManagerAdapter roleManagerAdapter, 118 TelecomSystem.SyncRoot lock) { 119 mContext = context; 120 mDefaultDialerManagerAdapter = defaultDialerManagerAdapter; 121 mRoleManagerAdapter = roleManagerAdapter; 122 123 Resources resources = mContext.getResources(); 124 mSystemDialerComponentName = new ComponentName(resources.getString( 125 com.android.internal.R.string.config_defaultDialer), 126 resources.getString(R.string.incall_default_class)); 127 128 IntentFilter packageIntentFilter = new IntentFilter(); 129 packageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 130 packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 131 packageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 132 packageIntentFilter.addDataScheme("package"); 133 packageIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 134 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, packageIntentFilter, null, null); 135 136 IntentFilter bootIntentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); 137 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, bootIntentFilter, null, null); 138 139 IntentFilter userRemovedFilter = new IntentFilter(Intent.ACTION_USER_REMOVED); 140 context.registerReceiver(mUserRemovedReceiver, userRemovedFilter); 141 142 Uri defaultDialerSetting = 143 Settings.Secure.getUriFor(Settings.Secure.DIALER_DEFAULT_APPLICATION); 144 context.getContentResolver() 145 .registerContentObserver(defaultDialerSetting, false, mDefaultDialerObserver, 146 UserHandle.USER_ALL); 147 } 148 getBTInCallServicePackages()149 public String[] getBTInCallServicePackages() { 150 return mRoleManagerAdapter.getBTInCallService(); 151 } 152 getDefaultDialerApplication(int userId)153 public String getDefaultDialerApplication(int userId) { 154 if (userId == UserHandle.USER_CURRENT) { 155 userId = ActivityManager.getCurrentUser(); 156 } 157 158 if (userId < 0) { 159 Log.w(LOG_TAG, "Attempting to get default dialer for a meta-user %d", userId); 160 return null; 161 } 162 163 // TODO: Re-enable this when we are able to use the cache once more. RoleManager does not 164 // provide a means for being informed when the role holder changes at the current time. 165 // 166 //synchronized (mLock) { 167 // String defaultDialer = mCurrentDefaultDialerPerUser.get(userId); 168 // if (!TextUtils.isEmpty(defaultDialer)) { 169 // return defaultDialer; 170 // } 171 //} 172 return refreshCacheForUser(userId); 173 } 174 getDefaultDialerApplication()175 public String getDefaultDialerApplication() { 176 return getDefaultDialerApplication(mContext.getUserId()); 177 } 178 setSystemDialerComponentName(ComponentName testComponentName)179 public void setSystemDialerComponentName(ComponentName testComponentName) { 180 mOverrideSystemDialerComponentName = testComponentName; 181 } 182 getSystemDialerApplication()183 public String getSystemDialerApplication() { 184 if (mOverrideSystemDialerComponentName != null) { 185 return mOverrideSystemDialerComponentName.getPackageName(); 186 } 187 return mSystemDialerComponentName.getPackageName(); 188 } 189 getSystemDialerComponent()190 public ComponentName getSystemDialerComponent() { 191 if (mOverrideSystemDialerComponentName != null) return mOverrideSystemDialerComponentName; 192 return mSystemDialerComponentName; 193 } 194 getDialtactsSystemDialerComponent()195 public ComponentName getDialtactsSystemDialerComponent() { 196 final Resources resources = mContext.getResources(); 197 return new ComponentName(getSystemDialerApplication(), 198 resources.getString(R.string.dialer_default_class)); 199 } 200 observeDefaultDialerApplication(Executor executor, IntConsumer observer)201 public void observeDefaultDialerApplication(Executor executor, IntConsumer observer) { 202 mRoleManagerAdapter.observeDefaultDialerApp(executor, observer); 203 } 204 isDefaultOrSystemDialer(String packageName, int userId)205 public boolean isDefaultOrSystemDialer(String packageName, int userId) { 206 String defaultDialer = getDefaultDialerApplication(userId); 207 return Objects.equals(packageName, defaultDialer) 208 || Objects.equals(packageName, getSystemDialerApplication()); 209 } 210 setDefaultDialer(String packageName, int userId)211 public boolean setDefaultDialer(String packageName, int userId) { 212 boolean isChanged = mDefaultDialerManagerAdapter.setDefaultDialerApplication( 213 mContext, packageName, userId); 214 if (isChanged) { 215 // Update the cache synchronously so that there is no delay in cache update. 216 mCurrentDefaultDialerPerUser.put(userId, packageName == null ? "" : packageName); 217 } 218 return isChanged; 219 } 220 refreshCacheForUser(int userId)221 private String refreshCacheForUser(int userId) { 222 String currentDefaultDialer = 223 mRoleManagerAdapter.getDefaultDialerApp(userId); 224 mCurrentDefaultDialerPerUser.put(userId, currentDefaultDialer == null ? "" : 225 currentDefaultDialer); 226 return currentDefaultDialer; 227 } 228 229 /** 230 * Refreshes the cache for users that currently have packageName as their cached default dialer. 231 * If packageName is null, refresh all caches. 232 * 233 * @param packageName Name of the affected package. 234 */ refreshCachesForUsersWithPackage(String packageName)235 private void refreshCachesForUsersWithPackage(String packageName) { 236 mCurrentDefaultDialerPerUser.forEach((userId, currentName) -> { 237 if (packageName == null || Objects.equals(packageName, currentName)) { 238 String newDefaultDialer = refreshCacheForUser(userId); 239 Log.v(LOG_TAG, "Refreshing default dialer for user %d: now %s", 240 userId, newDefaultDialer); 241 } 242 }); 243 } 244 dumpCache(IndentingPrintWriter pw)245 public void dumpCache(IndentingPrintWriter pw) { 246 mCurrentDefaultDialerPerUser.forEach((k, v) -> pw.printf("User %d: %s\n", k, v)); 247 } 248 removeUserFromCache(int userId)249 private void removeUserFromCache(int userId) { 250 mCurrentDefaultDialerPerUser.remove(userId); 251 } 252 253 /** 254 * registerContentObserver is really hard to mock out, so here is a getter method for the 255 * content observer for testing instead. 256 * 257 * @return The content observer 258 */ 259 @VisibleForTesting getContentObserver()260 public ContentObserver getContentObserver() { 261 return mDefaultDialerObserver; 262 } 263 getRoleManagerAdapter()264 public RoleManagerAdapter getRoleManagerAdapter() { 265 return mRoleManagerAdapter; 266 } 267 268 public interface DefaultDialerManagerAdapter { getDefaultDialerApplication(Context context)269 String getDefaultDialerApplication(Context context); 270 getDefaultDialerApplication(Context context, int userId)271 String getDefaultDialerApplication(Context context, int userId); 272 setDefaultDialerApplication(Context context, String packageName, int userId)273 boolean setDefaultDialerApplication(Context context, String packageName, int userId); 274 } 275 276 static class DefaultDialerManagerAdapterImpl implements DefaultDialerManagerAdapter { 277 @Override getDefaultDialerApplication(Context context)278 public String getDefaultDialerApplication(Context context) { 279 return DefaultDialerManager.getDefaultDialerApplication(context); 280 } 281 282 @Override getDefaultDialerApplication(Context context, int userId)283 public String getDefaultDialerApplication(Context context, int userId) { 284 return DefaultDialerManager.getDefaultDialerApplication(context, userId); 285 } 286 287 @Override setDefaultDialerApplication(Context context, String packageName, int userId)288 public boolean setDefaultDialerApplication(Context context, String packageName, 289 int userId) { 290 return DefaultDialerManager.setDefaultDialerApplication(context, packageName, userId); 291 } 292 } 293 } 294