Merge changes Icee8c85e,I98be6f30,I343b705b
* changes: [Smart forwarding] Enable/Disable Smart Forwarding flow [Smart forwarding] Add UI for Smart Forwarding [Smart forwarding] Add string and layout resource
This commit is contained in:
@@ -3672,6 +3672,12 @@
|
|||||||
<service android:name=".sim.SimNotificationService"
|
<service android:name=".sim.SimNotificationService"
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||||
|
|
||||||
|
<activity android:name=".sim.smartForwarding.SmartForwardingActivity"
|
||||||
|
android:theme="@style/Theme.SubSettings.Base"
|
||||||
|
android:exported="true"
|
||||||
|
android:launchMode="singleTask">
|
||||||
|
</activity>
|
||||||
|
|
||||||
<!-- This is the longest AndroidManifest.xml ever. -->
|
<!-- This is the longest AndroidManifest.xml ever. -->
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@@ -12627,4 +12627,29 @@
|
|||||||
|
|
||||||
<!-- Default preference title for showing all apps on device [CHAR_LIMIT=50]-->
|
<!-- Default preference title for showing all apps on device [CHAR_LIMIT=50]-->
|
||||||
<string name="default_see_all_apps_title">See all apps</string>
|
<string name="default_see_all_apps_title">See all apps</string>
|
||||||
|
|
||||||
|
<!-- Title for smart forwarding [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_title">Smart Forwarding</string>
|
||||||
|
<!-- Summary for smart forwarding enabled [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_summary_enabled">Smart Forwarding Enabled</string>
|
||||||
|
<!-- Summary for smart forwarding disabled [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_summary_disabled">Smart Forwarding Disabled</string>
|
||||||
|
<!-- Dialog title for smart forwarding ongoing [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_ongoing_title">Call Settings</string>
|
||||||
|
<!-- Subtext for smart forwarding ongoing [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_ongoing_text">Updating Settings...</string>
|
||||||
|
<!-- Dialog title for smart forwarding failed [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_failed_title">Call Settings error</string>
|
||||||
|
<!-- Subtext for smart forwarding failed [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_failed_text">Network or SIM card error.</string>
|
||||||
|
<!-- Subtext for sim is not activated [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_failed_not_activated_text">Sim is not activated.</string>
|
||||||
|
<!-- Title when smart forwarding can't get the phone number [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_input_mdn_title">Enter Phone numbers</string>
|
||||||
|
<!-- Dialog title when user update the phone number [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_input_mdn_dialog_title">Enter Phone number</string>
|
||||||
|
<!-- Alert Dialog text when user didn't input the phone number [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_missing_mdn_text">Phone number is missing.</string>
|
||||||
|
<!-- Alert Dialog text when user didn't input the phone number [CHAR LIMIT=50]-->
|
||||||
|
<string name="smart_forwarding_missing_alert_dialog_text">OK</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
27
res/xml/smart_forwarding_mdn_handler.xml
Normal file
27
res/xml/smart_forwarding_mdn_handler.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<fragment android:id="@+id/fragment_settings"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_above="@+id/cancel"
|
||||||
|
android:name="com.android.settings.sim.smartForwarding.MDNHandlerHeaderFragment"
|
||||||
|
android:layout_marginBottom="15dp" />
|
||||||
|
|
||||||
|
<Button android:id="@+id/process"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_margin="5dip"
|
||||||
|
android:text="process" />
|
||||||
|
|
||||||
|
<Button android:id="@+id/cancel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_margin="5dip"
|
||||||
|
android:text="cancel" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
18
res/xml/smart_forwarding_mdn_handler_header.xml
Normal file
18
res/xml/smart_forwarding_mdn_handler_header.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:key="network_and_internet_screen"
|
||||||
|
android:title="@string/smart_forwarding_input_mdn_title">
|
||||||
|
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="slot0_phone_number"
|
||||||
|
android:title="SIM 1"
|
||||||
|
android:dialogTitle="@string/smart_forwarding_input_mdn_dialog_title"
|
||||||
|
android:persistent="false" />
|
||||||
|
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="slot1_phone_number"
|
||||||
|
android:title="SIM 2"
|
||||||
|
android:dialogTitle="@string/smart_forwarding_input_mdn_dialog_title"
|
||||||
|
android:persistent="false" />
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
14
res/xml/smart_forwarding_switch.xml
Normal file
14
res/xml/smart_forwarding_switch.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:key="smart_forwarding_preference"
|
||||||
|
android:title="@string/smart_forwarding_title">
|
||||||
|
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="smart_forwarding_switch"
|
||||||
|
android:title="Smart forwarding"
|
||||||
|
android:summaryOff="@string/smart_forwarding_summary_disabled"
|
||||||
|
android:summaryOn="@string/smart_forwarding_summary_enabled"
|
||||||
|
android:disableDependentsState="true" />
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.sim.smartForwarding;
|
||||||
|
|
||||||
|
import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.TAG;
|
||||||
|
|
||||||
|
import android.telephony.CallForwardingInfo;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class DisableSmartForwardingTask implements Runnable {
|
||||||
|
private final TelephonyManager tm;
|
||||||
|
private final boolean[] callWaitingStatus;
|
||||||
|
private final CallForwardingInfo[] callForwardingInfo;
|
||||||
|
|
||||||
|
public DisableSmartForwardingTask(TelephonyManager tm,
|
||||||
|
boolean[] callWaitingStatus, CallForwardingInfo[] callForwardingInfo) {
|
||||||
|
this.tm = tm;
|
||||||
|
this.callWaitingStatus = callWaitingStatus;
|
||||||
|
this.callForwardingInfo = callForwardingInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (int i = 0; i < tm.getActiveModemCount(); i++) {
|
||||||
|
if (callWaitingStatus != null) {
|
||||||
|
Log.d(TAG, "Restore call waiting to " + callWaitingStatus[i]);
|
||||||
|
tm.setCallWaitingEnabled(callWaitingStatus[i], null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callForwardingInfo != null
|
||||||
|
&& callForwardingInfo[i] != null
|
||||||
|
&& callForwardingInfo[i].getTimeoutSeconds() > 0) {
|
||||||
|
Log.d(TAG, "Restore call waiting to " + callForwardingInfo);
|
||||||
|
tm.setCallForwarding(callForwardingInfo[i], null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,456 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.sim.smartForwarding;
|
||||||
|
|
||||||
|
import static android.telephony.CallForwardingInfo.REASON_NOT_REACHABLE;
|
||||||
|
|
||||||
|
import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.TAG;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.telephony.CallForwardingInfo;
|
||||||
|
import android.telephony.SubscriptionManager;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class EnableSmartForwardingTask
|
||||||
|
implements Callable<EnableSmartForwardingTask.FeatureResult> {
|
||||||
|
|
||||||
|
private static final int TIMEOUT = 20;
|
||||||
|
|
||||||
|
private final SubscriptionManager sm;
|
||||||
|
private final TelephonyManager tm;
|
||||||
|
private final String[] mCallForwardingNumber;
|
||||||
|
|
||||||
|
FeatureResult mResult = new FeatureResult(false, null);
|
||||||
|
SettableFuture<FeatureResult> client = SettableFuture.create();
|
||||||
|
|
||||||
|
public EnableSmartForwardingTask(Context context, String[] callForwardingNumber) {
|
||||||
|
tm = context.getSystemService(TelephonyManager.class);
|
||||||
|
sm = context.getSystemService(SubscriptionManager.class);
|
||||||
|
mCallForwardingNumber = callForwardingNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FeatureResult call() throws TimeoutException, InterruptedException, ExecutionException {
|
||||||
|
FlowController controller = new FlowController();
|
||||||
|
if (controller.init(mCallForwardingNumber)) {
|
||||||
|
controller.startProcess();
|
||||||
|
} else {
|
||||||
|
client.set(mResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.get(TIMEOUT, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
class FlowController {
|
||||||
|
private SlotUTData[] mSlotUTData;
|
||||||
|
private final ArrayList<Command> mSteps = new ArrayList<>();
|
||||||
|
|
||||||
|
public boolean init(String[] phoneNum) {
|
||||||
|
if (!initObject(phoneNum)) return false;
|
||||||
|
initSteps();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean initObject(String[] phoneNum) {
|
||||||
|
Executor executor = Executors.newSingleThreadExecutor();
|
||||||
|
if (tm == null || sm == null) {
|
||||||
|
Log.e(TAG, "TelephonyManager or SubscriptionManager is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phoneNum.length != tm.getActiveModemCount()) {
|
||||||
|
Log.e(TAG, "The length of PhoneNum array should same as phone count.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSlotUTData = new SlotUTData[tm.getActiveModemCount()];
|
||||||
|
for (int i = 0; i < mSlotUTData.length; i++) {
|
||||||
|
int[] subIdList = sm.getSubscriptionIds(i);
|
||||||
|
if (subIdList.length < 1) {
|
||||||
|
Log.e(TAG, "getSubscriptionIds() return empty sub id list.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int subId = subIdList[0];
|
||||||
|
|
||||||
|
if (!sm.isActiveSubId(subId)) {
|
||||||
|
mResult.setReason(FeatureResult.FailedReason.SIM_NOT_ACTIVE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryCallWaitingCommand queryCallWaitingCommand =
|
||||||
|
new QueryCallWaitingCommand(tm, executor, subId);
|
||||||
|
QueryCallForwardingCommand queryCallForwardingCommand =
|
||||||
|
new QueryCallForwardingCommand(tm, executor, subId);
|
||||||
|
UpdateCallWaitingCommand updateCallWaitingCommand =
|
||||||
|
new UpdateCallWaitingCommand(tm, executor, queryCallWaitingCommand, subId);
|
||||||
|
UpdateCallForwardingCommand updateCallForwardingCommand =
|
||||||
|
new UpdateCallForwardingCommand(tm, executor, queryCallForwardingCommand,
|
||||||
|
subId, phoneNum[i]);
|
||||||
|
|
||||||
|
mSlotUTData[i] = new SlotUTData(subId, phoneNum[i],
|
||||||
|
queryCallWaitingCommand,
|
||||||
|
queryCallForwardingCommand,
|
||||||
|
updateCallWaitingCommand,
|
||||||
|
updateCallForwardingCommand);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initSteps() {
|
||||||
|
// 1. Query call waiting for each slots
|
||||||
|
for (SlotUTData slotUTData : mSlotUTData) {
|
||||||
|
mSteps.add(slotUTData.getQueryCallWaitingCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Query call forwarding for each slots
|
||||||
|
for (SlotUTData slotUTData : mSlotUTData) {
|
||||||
|
mSteps.add(slotUTData.getQueryCallForwardingCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Enable call waiting for each slots
|
||||||
|
for (SlotUTData slotUTData : mSlotUTData) {
|
||||||
|
mSteps.add(slotUTData.getUpdateCallWaitingCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Set call forwarding for each slots
|
||||||
|
for (SlotUTData slotUTData : mSlotUTData) {
|
||||||
|
mSteps.add(slotUTData.getUpdateCallForwardingCommand());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startProcess() {
|
||||||
|
int index = 0;
|
||||||
|
boolean result = true;
|
||||||
|
|
||||||
|
// go through all steps
|
||||||
|
while (index < mSteps.size() && result) {
|
||||||
|
Command currentStep = mSteps.get(index);
|
||||||
|
Log.d(TAG, "processing : " + currentStep);
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = currentStep.process();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.d(TAG, "Failed on : " + currentStep, e);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
index++;
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Failed on : " + currentStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
// No more steps need to perform, return successful to UI.
|
||||||
|
mResult.result = true;
|
||||||
|
mResult.slotUTData = mSlotUTData;
|
||||||
|
Log.d(TAG, "Smart forwarding successful");
|
||||||
|
client.set(mResult);
|
||||||
|
} else {
|
||||||
|
restoreAllSteps(index);
|
||||||
|
client.set(mResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreAllSteps(int index) {
|
||||||
|
List<Command> restoreCommands = mSteps.subList(0, index);
|
||||||
|
Collections.reverse(restoreCommands);
|
||||||
|
for (Command currentStep : restoreCommands) {
|
||||||
|
Log.d(TAG, "restoreStep: " + currentStep);
|
||||||
|
// Only restore update steps
|
||||||
|
if (currentStep instanceof UpdateCommand) {
|
||||||
|
((UpdateCommand) currentStep).onRestore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class SlotUTData {
|
||||||
|
int subId;
|
||||||
|
String mCallForwardingNumber;
|
||||||
|
|
||||||
|
QueryCallWaitingCommand mQueryCallWaiting;
|
||||||
|
QueryCallForwardingCommand mQueryCallForwarding;
|
||||||
|
UpdateCallWaitingCommand mUpdateCallWaiting;
|
||||||
|
UpdateCallForwardingCommand mUpdateCallForwarding;
|
||||||
|
|
||||||
|
public SlotUTData(int subId,
|
||||||
|
String callForwardingNumber,
|
||||||
|
QueryCallWaitingCommand queryCallWaiting,
|
||||||
|
QueryCallForwardingCommand queryCallForwarding,
|
||||||
|
UpdateCallWaitingCommand updateCallWaiting,
|
||||||
|
UpdateCallForwardingCommand updateCallForwarding) {
|
||||||
|
this.subId = subId;
|
||||||
|
this.mCallForwardingNumber = callForwardingNumber;
|
||||||
|
this.mQueryCallWaiting = queryCallWaiting;
|
||||||
|
this.mQueryCallForwarding = queryCallForwarding;
|
||||||
|
this.mUpdateCallWaiting = updateCallWaiting;
|
||||||
|
this.mUpdateCallForwarding = updateCallForwarding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryCallWaitingCommand getQueryCallWaitingCommand() {
|
||||||
|
return mQueryCallWaiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryCallForwardingCommand getQueryCallForwardingCommand() {
|
||||||
|
return mQueryCallForwarding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateCallWaitingCommand getUpdateCallWaitingCommand() {
|
||||||
|
return mUpdateCallWaiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateCallForwardingCommand getUpdateCallForwardingCommand() {
|
||||||
|
return mUpdateCallForwarding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Command {
|
||||||
|
boolean process() throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract static class QueryCommand<T> implements Command {
|
||||||
|
int subId;
|
||||||
|
TelephonyManager tm;
|
||||||
|
Executor executor;
|
||||||
|
|
||||||
|
public QueryCommand(TelephonyManager tm, Executor executor, int subId) {
|
||||||
|
this.subId = subId;
|
||||||
|
this.tm = tm;
|
||||||
|
this.executor = executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.getClass().getSimpleName() + "[SubId " + subId + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract T getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract static class UpdateCommand<T> implements Command {
|
||||||
|
int subId;
|
||||||
|
TelephonyManager tm;
|
||||||
|
Executor executor;
|
||||||
|
|
||||||
|
public UpdateCommand(TelephonyManager tm, Executor executor, int subId) {
|
||||||
|
this.subId = subId;
|
||||||
|
this.tm = tm;
|
||||||
|
this.executor = executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.getClass().getSimpleName() + "[SubId " + subId + "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void onRestore();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class QueryCallWaitingCommand extends QueryCommand<Integer> {
|
||||||
|
int result;
|
||||||
|
SettableFuture<Boolean> resultFuture = SettableFuture.create();
|
||||||
|
|
||||||
|
public QueryCallWaitingCommand(TelephonyManager tm, Executor executor, int subId) {
|
||||||
|
super(tm, executor, subId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean process() throws Exception {
|
||||||
|
tm.createForSubscriptionId(subId)
|
||||||
|
.getCallWaitingStatus(executor, this::queryStatusCallBack);
|
||||||
|
return resultFuture.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Integer getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void queryStatusCallBack(int result) {
|
||||||
|
this.result = result;
|
||||||
|
|
||||||
|
if (result == TelephonyManager.CALL_WAITING_STATUS_ENABLED
|
||||||
|
|| result == TelephonyManager.CALL_WAITING_STATUS_DISABLED) {
|
||||||
|
Log.d(TAG, "Call Waiting result: " + result);
|
||||||
|
resultFuture.set(true);
|
||||||
|
} else {
|
||||||
|
resultFuture.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class QueryCallForwardingCommand extends QueryCommand<CallForwardingInfo> {
|
||||||
|
CallForwardingInfo result;
|
||||||
|
SettableFuture<Boolean> resultFuture = SettableFuture.create();
|
||||||
|
|
||||||
|
public QueryCallForwardingCommand(TelephonyManager tm, Executor executor, int subId) {
|
||||||
|
super(tm, executor, subId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean process() throws Exception{
|
||||||
|
tm.createForSubscriptionId(subId)
|
||||||
|
.getCallForwarding(REASON_NOT_REACHABLE, executor,
|
||||||
|
new TelephonyManager.CallForwardingInfoCallback() {
|
||||||
|
@Override
|
||||||
|
public void onCallForwardingInfoAvailable(CallForwardingInfo info) {
|
||||||
|
Log.d(TAG, "Call Forwarding result: " + info);
|
||||||
|
result = info;
|
||||||
|
resultFuture.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(int error) {
|
||||||
|
Log.d(TAG, "Query Call Forwarding failed.");
|
||||||
|
resultFuture.set(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return resultFuture.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
CallForwardingInfo getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class UpdateCallWaitingCommand extends UpdateCommand<Integer> {
|
||||||
|
SettableFuture<Boolean> resultFuture = SettableFuture.create();
|
||||||
|
QueryCallWaitingCommand queryResult;
|
||||||
|
|
||||||
|
public UpdateCallWaitingCommand(TelephonyManager tm, Executor executor,
|
||||||
|
QueryCallWaitingCommand queryCallWaitingCommand, int subId) {
|
||||||
|
super(tm, executor, subId);
|
||||||
|
this.queryResult = queryCallWaitingCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean process() throws Exception {
|
||||||
|
tm.createForSubscriptionId(subId)
|
||||||
|
.setCallWaitingEnabled(true, executor, this::updateStatusCallBack);
|
||||||
|
return resultFuture.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateStatusCallBack(int result) {
|
||||||
|
Log.d(TAG, "UpdateCallWaitingCommand updateStatusCallBack result: " + result);
|
||||||
|
if (result == TelephonyManager.CALL_WAITING_STATUS_ENABLED
|
||||||
|
|| result == TelephonyManager.CALL_WAITING_STATUS_DISABLED) {
|
||||||
|
resultFuture.set(true);
|
||||||
|
} else {
|
||||||
|
resultFuture.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void onRestore() {
|
||||||
|
Log.d(TAG, "onRestore: " + this);
|
||||||
|
if (queryResult.getResult() != TelephonyManager.CALL_WAITING_STATUS_ENABLED) {
|
||||||
|
tm.createForSubscriptionId(subId)
|
||||||
|
.setCallWaitingEnabled(false, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class UpdateCallForwardingCommand extends UpdateCommand<Integer> {
|
||||||
|
String phoneNum;
|
||||||
|
SettableFuture<Boolean> resultFuture = SettableFuture.create();
|
||||||
|
QueryCallForwardingCommand queryResult;
|
||||||
|
|
||||||
|
public UpdateCallForwardingCommand(TelephonyManager tm, Executor executor,
|
||||||
|
QueryCallForwardingCommand queryCallForwardingCommand,
|
||||||
|
int subId, String phoneNum) {
|
||||||
|
super(tm, executor, subId);
|
||||||
|
this.phoneNum = phoneNum;
|
||||||
|
this.queryResult = queryCallForwardingCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean process() throws Exception {
|
||||||
|
CallForwardingInfo info = new CallForwardingInfo(
|
||||||
|
true, REASON_NOT_REACHABLE, phoneNum, 3);
|
||||||
|
tm.createForSubscriptionId(subId)
|
||||||
|
.setCallForwarding(info, executor, this::updateStatusCallBack);
|
||||||
|
return resultFuture.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateStatusCallBack(int result) {
|
||||||
|
Log.d(TAG, "UpdateCallForwardingCommand updateStatusCallBack : " + result);
|
||||||
|
if (result == TelephonyManager.CallForwardingInfoCallback.RESULT_SUCCESS) {
|
||||||
|
resultFuture.set(true);
|
||||||
|
} else {
|
||||||
|
resultFuture.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void onRestore() {
|
||||||
|
Log.d(TAG, "onRestore: " + this);
|
||||||
|
|
||||||
|
tm.createForSubscriptionId(subId)
|
||||||
|
.setCallForwarding(queryResult.getResult(), null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FeatureResult {
|
||||||
|
enum FailedReason {
|
||||||
|
NETWORK_ERROR,
|
||||||
|
SIM_NOT_ACTIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean result;
|
||||||
|
private FailedReason reason;
|
||||||
|
private SlotUTData[] slotUTData;
|
||||||
|
|
||||||
|
public FeatureResult(boolean result, SlotUTData[] slotUTData) {
|
||||||
|
this.result = result;
|
||||||
|
this.slotUTData = slotUTData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotUTData[] getSlotUTData() {
|
||||||
|
return slotUTData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReason(FailedReason reason) {
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FailedReason getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.sim.smartForwarding;
|
||||||
|
|
||||||
|
import static com.android.settings.sim.smartForwarding.MDNHandlerHeaderFragment.KEY_SLOT0_PHONE_NUMBER;
|
||||||
|
import static com.android.settings.sim.smartForwarding.MDNHandlerHeaderFragment.KEY_SLOT1_PHONE_NUMBER;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||||
|
|
||||||
|
public class MDNHandlerFragment extends Fragment implements Instrumentable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.xml.smart_forwarding_mdn_handler, container, false);
|
||||||
|
getActivity().getActionBar().setTitle(
|
||||||
|
getResources().getString(R.string.smart_forwarding_input_mdn_title));
|
||||||
|
|
||||||
|
Button processBtn = view.findViewById(R.id.process);
|
||||||
|
processBtn.setOnClickListener((View v)-> {
|
||||||
|
pressButtonOnClick();
|
||||||
|
});
|
||||||
|
|
||||||
|
Button cancelBtn = view.findViewById(R.id.cancel);
|
||||||
|
cancelBtn.setOnClickListener((View v)-> {
|
||||||
|
switchToMainFragment(true);
|
||||||
|
});
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pressButtonOnClick() {
|
||||||
|
// Get the phone number from the UI
|
||||||
|
MDNHandlerHeaderFragment fragment = (MDNHandlerHeaderFragment) this
|
||||||
|
.getChildFragmentManager()
|
||||||
|
.findFragmentById(R.id.fragment_settings);
|
||||||
|
|
||||||
|
String slot0Number = "";
|
||||||
|
String slot1Number = "";
|
||||||
|
if (fragment != null) {
|
||||||
|
slot0Number = fragment.findPreference(KEY_SLOT0_PHONE_NUMBER)
|
||||||
|
.getSummary().toString();
|
||||||
|
slot1Number = fragment.findPreference(KEY_SLOT1_PHONE_NUMBER)
|
||||||
|
.getSummary().toString();
|
||||||
|
}
|
||||||
|
final String[] phoneNumber = {slot1Number, slot0Number};
|
||||||
|
|
||||||
|
// If phone number is empty, popup an alert dialog
|
||||||
|
if(TextUtils.isEmpty(phoneNumber[0])
|
||||||
|
|| TextUtils.isEmpty(phoneNumber[1])) {
|
||||||
|
new AlertDialog.Builder(getActivity())
|
||||||
|
.setTitle(R.string.smart_forwarding_failed_title)
|
||||||
|
.setMessage(R.string.smart_forwarding_missing_mdn_text)
|
||||||
|
.setPositiveButton(
|
||||||
|
R.string.smart_forwarding_missing_alert_dialog_text,
|
||||||
|
(dialog, which) -> { dialog.dismiss(); })
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
switchToMainFragment(false);
|
||||||
|
((SmartForwardingActivity)getActivity()).enableSmartForwarding(phoneNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void switchToMainFragment(boolean turnoffSwitch) {
|
||||||
|
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
|
||||||
|
fragmentManager.beginTransaction()
|
||||||
|
.replace(R.id.content_frame, new SmartForwardingFragment(turnoffSwitch))
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
return SettingsEnums.MOBILE_NETWORK;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.sim.smartForwarding;
|
||||||
|
|
||||||
|
import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.getPhoneNumber;
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.InputType;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.preference.EditTextPreference;
|
||||||
|
import androidx.preference.EditTextPreference.OnBindEditTextListener;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||||
|
|
||||||
|
public class MDNHandlerHeaderFragment extends PreferenceFragmentCompat
|
||||||
|
implements Preference.OnPreferenceChangeListener, OnBindEditTextListener, Instrumentable {
|
||||||
|
|
||||||
|
public static final String KEY_SLOT0_PHONE_NUMBER = "slot0_phone_number";
|
||||||
|
public static final String KEY_SLOT1_PHONE_NUMBER = "slot1_phone_number";
|
||||||
|
|
||||||
|
public MDNHandlerHeaderFragment() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||||
|
setPreferencesFromResource(R.xml.smart_forwarding_mdn_handler_header, rootKey);
|
||||||
|
|
||||||
|
EditTextPreference slot0EditText = findPreference(KEY_SLOT0_PHONE_NUMBER);
|
||||||
|
slot0EditText.setOnBindEditTextListener(this);
|
||||||
|
slot0EditText.setOnPreferenceChangeListener(this);
|
||||||
|
String slot0PhoneNumber = getPhoneNumber(getContext(), 0);
|
||||||
|
slot0EditText.setSummary(slot0PhoneNumber);
|
||||||
|
slot0EditText.setText(slot0PhoneNumber);
|
||||||
|
|
||||||
|
EditTextPreference slot1EditText = findPreference(KEY_SLOT1_PHONE_NUMBER);
|
||||||
|
slot1EditText.setOnPreferenceChangeListener(this);
|
||||||
|
slot1EditText.setOnBindEditTextListener(this);
|
||||||
|
String slot1PhoneNumber = getPhoneNumber(getContext(), 1);
|
||||||
|
slot1EditText.setSummary(slot1PhoneNumber);
|
||||||
|
slot1EditText.setText(slot1PhoneNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
preference.setSummary(newValue.toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindEditText(@NonNull EditText editText) {
|
||||||
|
editText.setInputType(InputType.TYPE_CLASS_PHONE);
|
||||||
|
editText.setSingleLine(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
return SettingsEnums.MOBILE_NETWORK;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.sim.smartForwarding;
|
||||||
|
|
||||||
|
import static com.android.settings.sim.smartForwarding.EnableSmartForwardingTask.FeatureResult;
|
||||||
|
import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.TAG;
|
||||||
|
import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.backupPrevStatus;
|
||||||
|
import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.clearAllBackupData;
|
||||||
|
import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.getAllSlotCallForwardingStatus;
|
||||||
|
import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.getAllSlotCallWaitingStatus;
|
||||||
|
|
||||||
|
import android.app.ActionBar;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.telephony.CallForwardingInfo;
|
||||||
|
import android.telephony.SubscriptionManager;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Toolbar;
|
||||||
|
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.SettingsBaseActivity;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class SmartForwardingActivity extends SettingsBaseActivity {
|
||||||
|
final ListeningExecutorService service =
|
||||||
|
MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
final Toolbar toolbar = findViewById(R.id.action_bar);
|
||||||
|
toolbar.setVisibility(View.VISIBLE);
|
||||||
|
setActionBar(toolbar);
|
||||||
|
|
||||||
|
final ActionBar actionBar = getActionBar();
|
||||||
|
if (actionBar != null) {
|
||||||
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSupportFragmentManager()
|
||||||
|
.beginTransaction()
|
||||||
|
.replace(R.id.content_frame, new SmartForwardingFragment())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enableSmartForwarding(String[] phoneNumber) {
|
||||||
|
// Pop-up ongoing dialog
|
||||||
|
ProgressDialog dialog = new ProgressDialog(this);
|
||||||
|
dialog.setTitle(R.string.smart_forwarding_ongoing_title);
|
||||||
|
dialog.setIndeterminate(true);
|
||||||
|
dialog.setMessage(getText(R.string.smart_forwarding_ongoing_text));
|
||||||
|
dialog.setCancelable(false);
|
||||||
|
dialog.show();
|
||||||
|
|
||||||
|
// Enable feature
|
||||||
|
ListenableFuture<FeatureResult> enableTask =
|
||||||
|
service.submit(new EnableSmartForwardingTask(this, phoneNumber));
|
||||||
|
Futures.addCallback(enableTask, new FutureCallback<FeatureResult>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(FeatureResult result) {
|
||||||
|
Log.e(TAG, "Enable Feature result: " + result.getResult());
|
||||||
|
if (result.getResult()) {
|
||||||
|
backupPrevStatus(SmartForwardingActivity.this, result.getSlotUTData());
|
||||||
|
|
||||||
|
// Turn on switch preference
|
||||||
|
SmartForwardingFragment fragment =
|
||||||
|
(SmartForwardingFragment) getSupportFragmentManager()
|
||||||
|
.findFragmentById(R.id.content_frame);
|
||||||
|
if (fragment != null) {
|
||||||
|
fragment.turnOnSwitchPreference();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onError(result);
|
||||||
|
}
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
Log.e(TAG, "Enable Feature exception", t);
|
||||||
|
dialog.dismiss();
|
||||||
|
|
||||||
|
// Pop-up error dialog
|
||||||
|
AlertDialog mDialog = new AlertDialog.Builder(SmartForwardingActivity.this)
|
||||||
|
.setTitle(R.string.smart_forwarding_failed_title)
|
||||||
|
.setMessage(R.string.smart_forwarding_failed_text)
|
||||||
|
.setPositiveButton(
|
||||||
|
R.string.smart_forwarding_missing_alert_dialog_text,
|
||||||
|
(dialog, which) -> { dialog.dismiss(); })
|
||||||
|
.create();
|
||||||
|
mDialog.show();
|
||||||
|
}
|
||||||
|
}, ContextCompat.getMainExecutor(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disableSmartForwarding() {
|
||||||
|
TelephonyManager tm = getSystemService(TelephonyManager.class);
|
||||||
|
SubscriptionManager sm = getSystemService(SubscriptionManager.class);
|
||||||
|
|
||||||
|
boolean[] callWaitingStatus = getAllSlotCallWaitingStatus(this, sm, tm);
|
||||||
|
CallForwardingInfo[] callForwardingInfo = getAllSlotCallForwardingStatus(this, sm, tm);
|
||||||
|
|
||||||
|
// Disable feature
|
||||||
|
ListenableFuture disableTask = service.submit(new DisableSmartForwardingTask(
|
||||||
|
tm, callWaitingStatus, callForwardingInfo));
|
||||||
|
Futures.addCallback(disableTask, new FutureCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Object result) {
|
||||||
|
clearAllBackupData(SmartForwardingActivity.this, sm, tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
Log.e(TAG, "Disable Feature exception" + t);
|
||||||
|
}
|
||||||
|
}, ContextCompat.getMainExecutor(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onError(FeatureResult result) {
|
||||||
|
int errorMsg;
|
||||||
|
if (result.getReason() == FeatureResult.FailedReason.SIM_NOT_ACTIVE) {
|
||||||
|
errorMsg = R.string.smart_forwarding_failed_not_activated_text;
|
||||||
|
} else {
|
||||||
|
errorMsg = R.string.smart_forwarding_failed_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop-up error dialog
|
||||||
|
AlertDialog mDialog = new AlertDialog.Builder(SmartForwardingActivity.this)
|
||||||
|
.setTitle(R.string.smart_forwarding_failed_title)
|
||||||
|
.setMessage(errorMsg)
|
||||||
|
.setPositiveButton(
|
||||||
|
R.string.smart_forwarding_missing_alert_dialog_text,
|
||||||
|
(dialog, which) -> { dialog.dismiss(); })
|
||||||
|
.create();
|
||||||
|
mDialog.show();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.sim.smartForwarding;
|
||||||
|
|
||||||
|
import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.TAG;
|
||||||
|
import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.getPhoneNumber;
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
|
import androidx.preference.SwitchPreference;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||||
|
|
||||||
|
public class SmartForwardingFragment extends PreferenceFragmentCompat
|
||||||
|
implements Preference.OnPreferenceChangeListener, Instrumentable {
|
||||||
|
|
||||||
|
private static final String KEY_SMART_FORWARDING_SWITCH = "smart_forwarding_switch";
|
||||||
|
private boolean turnOffSwitch;
|
||||||
|
|
||||||
|
public SmartForwardingFragment() { }
|
||||||
|
|
||||||
|
public SmartForwardingFragment(boolean turnOffSwitch) {
|
||||||
|
this.turnOffSwitch = turnOffSwitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||||
|
setPreferencesFromResource(R.xml.smart_forwarding_switch, rootKey);
|
||||||
|
|
||||||
|
String title = getResources().getString(R.string.smart_forwarding_title);
|
||||||
|
getActivity().getActionBar().setTitle(title);
|
||||||
|
|
||||||
|
SwitchPreference smartForwardingSwitch = findPreference(KEY_SMART_FORWARDING_SWITCH);
|
||||||
|
if (turnOffSwitch) {
|
||||||
|
smartForwardingSwitch.setChecked(false);
|
||||||
|
}
|
||||||
|
smartForwardingSwitch.setOnPreferenceChangeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
boolean value = (boolean) newValue;
|
||||||
|
|
||||||
|
Log.d(TAG, "onPreferenceChange. Update value to " + value);
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
String slot0PhoneNumber = getPhoneNumber(getContext(), 0);
|
||||||
|
String slot1PhoneNumber = getPhoneNumber(getContext(), 1);
|
||||||
|
|
||||||
|
String[] phoneNumber = new String[]{slot1PhoneNumber, slot0PhoneNumber};
|
||||||
|
|
||||||
|
if (TextUtils.isEmpty(slot0PhoneNumber) || TextUtils.isEmpty(slot1PhoneNumber)) {
|
||||||
|
Log.d(TAG, "Slot 0 or Slot 1 phone number missing.");
|
||||||
|
switchToMDNFragment();
|
||||||
|
} else {
|
||||||
|
((SmartForwardingActivity) getActivity()).enableSmartForwarding(phoneNumber);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
((SmartForwardingActivity) getActivity()).disableSmartForwarding();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void switchToMDNFragment() {
|
||||||
|
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
|
||||||
|
fragmentManager.beginTransaction()
|
||||||
|
.replace(R.id.content_frame, new MDNHandlerFragment())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void turnOnSwitchPreference() {
|
||||||
|
SwitchPreference smartForwardingSwitch = findPreference(KEY_SMART_FORWARDING_SWITCH);
|
||||||
|
smartForwardingSwitch.setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
return SettingsEnums.MOBILE_NETWORK;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.sim.smartForwarding;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.telephony.CallForwardingInfo;
|
||||||
|
import android.telephony.SubscriptionInfo;
|
||||||
|
import android.telephony.SubscriptionManager;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
|
||||||
|
public class SmartForwardingUtils {
|
||||||
|
public static final String TAG = "SmartForwarding";
|
||||||
|
public static final String SMART_FORWARDING_PREF = "smart_forwarding_pref_";
|
||||||
|
|
||||||
|
public static final String CALL_WAITING_KEY = "call_waiting_key";
|
||||||
|
public static final String CALL_FORWARDING_ENABLED_KEY = "call_forwarding_enabled_key";
|
||||||
|
public static final String CALL_FORWARDING_REASON_KEY = "call_forwarding_reason_key";
|
||||||
|
public static final String CALL_FORWARDING_NUMBER_KEY = "call_forwarding_number_key";
|
||||||
|
public static final String CALL_FORWARDING_TIME_KEY = "call_forwarding_timekey";
|
||||||
|
|
||||||
|
public static boolean getBackupCallWaitingStatus(Context context, int subId) {
|
||||||
|
SharedPreferences preferences = context.getSharedPreferences(
|
||||||
|
SMART_FORWARDING_PREF + subId, Context.MODE_PRIVATE);
|
||||||
|
return preferences.getBoolean(CALL_WAITING_KEY, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CallForwardingInfo getBackupCallForwardingStatus(Context context, int subId) {
|
||||||
|
SharedPreferences preferences = context.getSharedPreferences(
|
||||||
|
SMART_FORWARDING_PREF + subId, Context.MODE_PRIVATE);
|
||||||
|
if (preferences.contains(CALL_FORWARDING_ENABLED_KEY)) {
|
||||||
|
boolean enabled = preferences.getBoolean(CALL_FORWARDING_ENABLED_KEY, false);
|
||||||
|
int reason = preferences.getInt(CALL_FORWARDING_REASON_KEY,
|
||||||
|
CallForwardingInfo.REASON_UNCONDITIONAL);
|
||||||
|
String number = preferences.getString(CALL_FORWARDING_NUMBER_KEY, "");
|
||||||
|
int time = preferences.getInt(CALL_FORWARDING_TIME_KEY, 1);
|
||||||
|
|
||||||
|
return new CallForwardingInfo(enabled, reason, number, time);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveCallWaitingStatus(Context context, int subId, boolean value) {
|
||||||
|
SharedPreferences.Editor preferences = context.getSharedPreferences(
|
||||||
|
SMART_FORWARDING_PREF + subId, Context.MODE_PRIVATE).edit();
|
||||||
|
preferences.putBoolean(CALL_WAITING_KEY, value).commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveCallForwardingStatus(Context context, int subId,
|
||||||
|
CallForwardingInfo callForwardingInfo) {
|
||||||
|
SharedPreferences.Editor preferences = context.getSharedPreferences(
|
||||||
|
SMART_FORWARDING_PREF + subId, Context.MODE_PRIVATE).edit();
|
||||||
|
|
||||||
|
preferences.putBoolean(CALL_FORWARDING_ENABLED_KEY, callForwardingInfo.isEnabled())
|
||||||
|
.commit();
|
||||||
|
preferences.putInt(CALL_FORWARDING_REASON_KEY, callForwardingInfo.getReason()).commit();
|
||||||
|
preferences.putString(CALL_FORWARDING_NUMBER_KEY, callForwardingInfo.getNumber()).commit();
|
||||||
|
preferences.putInt(CALL_FORWARDING_TIME_KEY, callForwardingInfo.getTimeoutSeconds())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearBackupData(Context context, int subId) {
|
||||||
|
SharedPreferences.Editor preferences = context.getSharedPreferences(
|
||||||
|
SMART_FORWARDING_PREF + subId, Context.MODE_PRIVATE).edit();
|
||||||
|
preferences.clear().commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean[] getAllSlotCallWaitingStatus(Context context, SubscriptionManager sm,
|
||||||
|
TelephonyManager tm) {
|
||||||
|
int phoneCount = tm.getActiveModemCount();
|
||||||
|
boolean[] allStatus = new boolean[phoneCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < phoneCount; i++) {
|
||||||
|
int subId = sm.getSubscriptionIds(i)[0];
|
||||||
|
boolean callWaitingStatus = getBackupCallWaitingStatus(context, subId);
|
||||||
|
allStatus[i] = callWaitingStatus;
|
||||||
|
}
|
||||||
|
return allStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CallForwardingInfo[] getAllSlotCallForwardingStatus(
|
||||||
|
Context context, SubscriptionManager sm, TelephonyManager tm) {
|
||||||
|
int phoneCount = tm.getActiveModemCount();
|
||||||
|
CallForwardingInfo[] allStatus = new CallForwardingInfo[phoneCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < phoneCount; i++) {
|
||||||
|
int subId = sm.getSubscriptionIds(i)[0];
|
||||||
|
CallForwardingInfo callWaitingStatus = getBackupCallForwardingStatus(context, subId);
|
||||||
|
allStatus[i] = callWaitingStatus;
|
||||||
|
}
|
||||||
|
return allStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearAllBackupData(Context context, SubscriptionManager sm,
|
||||||
|
TelephonyManager tm) {
|
||||||
|
int phoneCount = tm.getActiveModemCount();
|
||||||
|
for (int i = 0; i < phoneCount; i++) {
|
||||||
|
int subId = sm.getSubscriptionIds(i)[0];
|
||||||
|
clearBackupData(context, subId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void backupPrevStatus(Context context,
|
||||||
|
EnableSmartForwardingTask.SlotUTData[] slotUTData) {
|
||||||
|
for (int i = 0; i < slotUTData.length; i++) {
|
||||||
|
int callWaiting = slotUTData[i].mQueryCallWaiting.result;
|
||||||
|
saveCallWaitingStatus(
|
||||||
|
context,
|
||||||
|
slotUTData[i].subId,
|
||||||
|
callWaiting == TelephonyManager.CALL_WAITING_STATUS_ENABLED);
|
||||||
|
|
||||||
|
saveCallForwardingStatus(
|
||||||
|
context,
|
||||||
|
slotUTData[i].subId,
|
||||||
|
slotUTData[i].mQueryCallForwarding.result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPhoneNumber(Context context, int slotId) {
|
||||||
|
SubscriptionManager subscriptionManager = context.getSystemService(
|
||||||
|
SubscriptionManager.class);
|
||||||
|
int[] subIdList = subscriptionManager.getSubscriptionIds(slotId);
|
||||||
|
if (subIdList != null) {
|
||||||
|
SubscriptionInfo subInfo = subscriptionManager.getActiveSubscriptionInfo(subIdList[0]);
|
||||||
|
return (subInfo != null) ? subInfo.getNumber() : "";
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user