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