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