• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }