blob: 3b36119fb663b418868ddf1c724a23eb8ef02c6b [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server.telecom;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.telecom.DefaultDialerManager;
import android.telecom.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import java.util.Objects;
public class DefaultDialerCache {
public interface DefaultDialerManagerAdapter {
String getDefaultDialerApplication(Context context);
String getDefaultDialerApplication(Context context, int userId);
boolean setDefaultDialerApplication(Context context, String packageName, int userId);
}
static class DefaultDialerManagerAdapterImpl implements DefaultDialerManagerAdapter {
@Override
public String getDefaultDialerApplication(Context context) {
return DefaultDialerManager.getDefaultDialerApplication(context);
}
@Override
public String getDefaultDialerApplication(Context context, int userId) {
return DefaultDialerManager.getDefaultDialerApplication(context, userId);
}
@Override
public boolean setDefaultDialerApplication(Context context, String packageName,
int userId) {
return DefaultDialerManager.setDefaultDialerApplication(context, packageName, userId);
}
}
private static final String LOG_TAG = "DefaultDialerCache";
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.startSession("DDC.oR");
try {
String packageName;
if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) {
packageName = null;
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
&& !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
packageName = intent.getData().getSchemeSpecificPart();
} else if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
packageName = null;
} else if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
packageName = null;
} else {
return;
}
synchronized (mLock) {
refreshCachesForUsersWithPackage(packageName);
}
} finally {
Log.endSession();
}
}
};
private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
int removedUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL);
if (removedUser == UserHandle.USER_NULL) {
Log.w(LOG_TAG, "Expected EXTRA_USER_HANDLE with ACTION_USER_REMOVED");
} else {
removeUserFromCache(removedUser);
Log.i(LOG_TAG, "Removing user %s", removedUser);
}
}
}
};
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final ContentObserver mDefaultDialerObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
Log.startSession("DDC.oC");
try {
// We don't get the user ID of the user that changed here, so we'll have to
// refresh all of the users.
synchronized (mLock) {
refreshCachesForUsersWithPackage(null);
}
} finally {
Log.endSession();
}
}
@Override
public boolean deliverSelfNotifications() {
return true;
}
};
private final Context mContext;
private final DefaultDialerManagerAdapter mDefaultDialerManagerAdapter;
private final TelecomSystem.SyncRoot mLock;
private final String mSystemDialerName;
private SparseArray<String> mCurrentDefaultDialerPerUser = new SparseArray<>();
public DefaultDialerCache(Context context,
DefaultDialerManagerAdapter defaultDialerManagerAdapter,
TelecomSystem.SyncRoot lock) {
mContext = context;
mDefaultDialerManagerAdapter = defaultDialerManagerAdapter;
mLock = lock;
mSystemDialerName = mContext.getResources().getString(R.string.ui_default_package);
IntentFilter packageIntentFilter = new IntentFilter();
packageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
packageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
packageIntentFilter.addDataScheme("package");
context.registerReceiverAsUser(mReceiver, UserHandle.ALL, packageIntentFilter, null, null);
IntentFilter bootIntentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
context.registerReceiverAsUser(mReceiver, UserHandle.ALL, bootIntentFilter, null, null);
IntentFilter userRemovedFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
context.registerReceiver(mUserRemovedReceiver, userRemovedFilter);
Uri defaultDialerSetting =
Settings.Secure.getUriFor(Settings.Secure.DIALER_DEFAULT_APPLICATION);
context.getContentResolver()
.registerContentObserver(defaultDialerSetting, false, mDefaultDialerObserver,
UserHandle.USER_ALL);
}
public String getDefaultDialerApplication(int userId) {
if (userId == UserHandle.USER_CURRENT) {
userId = ActivityManager.getCurrentUser();
}
if (userId < 0) {
Log.w(LOG_TAG, "Attempting to get default dialer for a meta-user %d", userId);
return null;
}
synchronized (mLock) {
String defaultDialer = mCurrentDefaultDialerPerUser.get(userId);
if (defaultDialer != null) {
return defaultDialer;
}
}
return refreshCacheForUser(userId);
}
public String getDefaultDialerApplication() {
return getDefaultDialerApplication(mContext.getUserId());
}
public boolean isDefaultOrSystemDialer(String packageName, int userId) {
String defaultDialer = getDefaultDialerApplication(userId);
return Objects.equals(packageName, defaultDialer)
|| Objects.equals(packageName, mSystemDialerName);
}
public boolean setDefaultDialer(String packageName, int userId) {
boolean isChanged = mDefaultDialerManagerAdapter.setDefaultDialerApplication(
mContext, packageName, userId);
if(isChanged) {
synchronized (mLock) {
// Update the cache synchronously so that there is no delay in cache update.
mCurrentDefaultDialerPerUser.put(userId, packageName);
}
}
return isChanged;
}
private String refreshCacheForUser(int userId) {
String currentDefaultDialer =
mDefaultDialerManagerAdapter.getDefaultDialerApplication(mContext, userId);
synchronized (mLock) {
mCurrentDefaultDialerPerUser.put(userId, currentDefaultDialer);
}
return currentDefaultDialer;
}
/**
* Refreshes the cache for users that currently have packageName as their cached default dialer.
* If packageName is null, refresh all caches.
* @param packageName Name of the affected package.
*/
private void refreshCachesForUsersWithPackage(String packageName) {
for (int i = 0; i < mCurrentDefaultDialerPerUser.size(); i++) {
int userId = mCurrentDefaultDialerPerUser.keyAt(i);
if (packageName == null ||
Objects.equals(packageName, mCurrentDefaultDialerPerUser.get(userId))) {
String newDefaultDialer = refreshCacheForUser(userId);
Log.i(LOG_TAG, "Refreshing default dialer for user %d: now %s",
userId, newDefaultDialer);
}
}
}
public void dumpCache(IndentingPrintWriter pw) {
synchronized (mLock) {
for (int i = 0; i < mCurrentDefaultDialerPerUser.size(); i++) {
pw.printf("User %d: %s\n", mCurrentDefaultDialerPerUser.keyAt(i),
mCurrentDefaultDialerPerUser.valueAt(i));
}
}
}
private void removeUserFromCache(int userId) {
synchronized (mLock) {
mCurrentDefaultDialerPerUser.remove(userId);
}
}
/**
* registerContentObserver is really hard to mock out, so here is a getter method for the
* content observer for testing instead.
* @return The content observer
*/
@VisibleForTesting
public ContentObserver getContentObserver() {
return mDefaultDialerObserver;
}
}