163 lines
6.2 KiB
Java
163 lines
6.2 KiB
Java
|
/*
|
||
|
* Copyright (C) 2015 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.voicemail.impl.sync;
|
||
|
|
||
|
import android.annotation.TargetApi;
|
||
|
import android.content.Context;
|
||
|
import android.os.Build.VERSION_CODES;
|
||
|
import android.os.UserManager;
|
||
|
import android.support.annotation.MainThread;
|
||
|
import android.support.annotation.NonNull;
|
||
|
import android.support.annotation.VisibleForTesting;
|
||
|
import android.telecom.PhoneAccountHandle;
|
||
|
import android.telecom.TelecomManager;
|
||
|
import android.util.ArraySet;
|
||
|
import com.android.dialer.common.Assert;
|
||
|
import com.android.dialer.common.PerAccountSharedPreferences;
|
||
|
import com.android.dialer.common.concurrent.ThreadUtil;
|
||
|
import com.android.dialer.storage.StorageComponent;
|
||
|
import com.android.voicemail.VoicemailClient.ActivationStateListener;
|
||
|
import com.android.voicemail.impl.OmtpConstants;
|
||
|
import com.android.voicemail.impl.VisualVoicemailPreferences;
|
||
|
import com.android.voicemail.impl.VoicemailStatus;
|
||
|
import com.android.voicemail.impl.sms.StatusMessage;
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.List;
|
||
|
import java.util.Set;
|
||
|
|
||
|
/**
|
||
|
* Tracks the activation state of a visual voicemail phone account. An account is considered
|
||
|
* activated if it has valid connection information from the {@link StatusMessage} stored on the
|
||
|
* device. Once activation/provisioning is completed, {@link #addAccount(Context,
|
||
|
* PhoneAccountHandle, StatusMessage)} should be called to store the connection information. When an
|
||
|
* account is removed or if the connection information is deemed invalid, {@link
|
||
|
* #removeAccount(Context, PhoneAccountHandle)} should be called to clear the connection information
|
||
|
* and allow reactivation.
|
||
|
*/
|
||
|
@TargetApi(VERSION_CODES.O)
|
||
|
public class VvmAccountManager {
|
||
|
public static final String TAG = "VvmAccountManager";
|
||
|
|
||
|
@VisibleForTesting static final String IS_ACCOUNT_ACTIVATED = "is_account_activated";
|
||
|
|
||
|
private static final Set<ActivationStateListener> listeners = new ArraySet<>();
|
||
|
|
||
|
public static void addAccount(
|
||
|
Context context, PhoneAccountHandle phoneAccountHandle, StatusMessage statusMessage) {
|
||
|
VisualVoicemailPreferences preferences =
|
||
|
new VisualVoicemailPreferences(context, phoneAccountHandle);
|
||
|
statusMessage.putStatus(preferences.edit()).apply();
|
||
|
setAccountActivated(context, phoneAccountHandle, true);
|
||
|
|
||
|
ThreadUtil.postOnUiThread(
|
||
|
() -> {
|
||
|
for (ActivationStateListener listener : listeners) {
|
||
|
listener.onActivationStateChanged(phoneAccountHandle, true);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public static void removeAccount(Context context, PhoneAccountHandle phoneAccount) {
|
||
|
VoicemailStatus.disable(context, phoneAccount);
|
||
|
setAccountActivated(context, phoneAccount, false);
|
||
|
VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(context, phoneAccount);
|
||
|
preferences
|
||
|
.edit()
|
||
|
.putString(OmtpConstants.IMAP_USER_NAME, null)
|
||
|
.putString(OmtpConstants.IMAP_PASSWORD, null)
|
||
|
.apply();
|
||
|
ThreadUtil.postOnUiThread(
|
||
|
() -> {
|
||
|
for (ActivationStateListener listener : listeners) {
|
||
|
listener.onActivationStateChanged(phoneAccount, false);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public static boolean isAccountActivated(Context context, PhoneAccountHandle phoneAccount) {
|
||
|
Assert.isNotNull(phoneAccount);
|
||
|
PerAccountSharedPreferences preferences =
|
||
|
getPreferenceForActivationState(context, phoneAccount);
|
||
|
migrateActivationState(context, preferences, phoneAccount);
|
||
|
return preferences.getBoolean(IS_ACCOUNT_ACTIVATED, false);
|
||
|
}
|
||
|
|
||
|
@NonNull
|
||
|
public static List<PhoneAccountHandle> getActiveAccounts(Context context) {
|
||
|
List<PhoneAccountHandle> results = new ArrayList<>();
|
||
|
for (PhoneAccountHandle phoneAccountHandle :
|
||
|
context.getSystemService(TelecomManager.class).getCallCapablePhoneAccounts()) {
|
||
|
if (isAccountActivated(context, phoneAccountHandle)) {
|
||
|
results.add(phoneAccountHandle);
|
||
|
}
|
||
|
}
|
||
|
return results;
|
||
|
}
|
||
|
|
||
|
@MainThread
|
||
|
public static void addListener(ActivationStateListener listener) {
|
||
|
Assert.isMainThread();
|
||
|
listeners.add(listener);
|
||
|
}
|
||
|
|
||
|
@MainThread
|
||
|
public static void removeListener(ActivationStateListener listener) {
|
||
|
Assert.isMainThread();
|
||
|
listeners.remove(listener);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The activation state is moved from credential protected storage to device protected storage
|
||
|
* after v10, so it can be checked under FBE. The state should be migrated to avoid reactivation.
|
||
|
*/
|
||
|
private static void migrateActivationState(
|
||
|
Context context,
|
||
|
PerAccountSharedPreferences deviceProtectedPreference,
|
||
|
PhoneAccountHandle phoneAccountHandle) {
|
||
|
if (!context.getSystemService(UserManager.class).isUserUnlocked()) {
|
||
|
return;
|
||
|
}
|
||
|
if (deviceProtectedPreference.contains(IS_ACCOUNT_ACTIVATED)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
PerAccountSharedPreferences credentialProtectedPreference =
|
||
|
new VisualVoicemailPreferences(context, phoneAccountHandle);
|
||
|
|
||
|
deviceProtectedPreference
|
||
|
.edit()
|
||
|
.putBoolean(
|
||
|
IS_ACCOUNT_ACTIVATED,
|
||
|
credentialProtectedPreference.getBoolean(IS_ACCOUNT_ACTIVATED, false))
|
||
|
.apply();
|
||
|
}
|
||
|
|
||
|
private static void setAccountActivated(
|
||
|
Context context, PhoneAccountHandle phoneAccountHandle, boolean activated) {
|
||
|
Assert.isNotNull(phoneAccountHandle);
|
||
|
getPreferenceForActivationState(context, phoneAccountHandle)
|
||
|
.edit()
|
||
|
.putBoolean(IS_ACCOUNT_ACTIVATED, activated)
|
||
|
.apply();
|
||
|
}
|
||
|
|
||
|
private static PerAccountSharedPreferences getPreferenceForActivationState(
|
||
|
Context context, PhoneAccountHandle phoneAccountHandle) {
|
||
|
return new PerAccountSharedPreferences(
|
||
|
context, phoneAccountHandle, StorageComponent.get(context).unencryptedSharedPrefs());
|
||
|
}
|
||
|
}
|