Expose requestModemActivityInfo
Expose requestModemActivityInfo in TelephonyManager using the Executor + Consumer pattern, and modify clients to use it. Test: atest TelephonyManagerTest#testRequestModemActivityInfo Fixes: 170427831 Change-Id: I7e8134c8058017b888c324a9f85d473fc3cdd8f5
This commit is contained in:
@@ -36671,6 +36671,11 @@ package android.os {
|
||||
ctor public OperationCanceledException(String);
|
||||
}
|
||||
|
||||
public interface OutcomeReceiver<R, E extends java.lang.Throwable> {
|
||||
method public default void onError(@NonNull E);
|
||||
method public void onResult(@NonNull R);
|
||||
}
|
||||
|
||||
public final class Parcel {
|
||||
method public void appendFrom(android.os.Parcel, int, int);
|
||||
method @Nullable public android.os.IBinder[] createBinderArray();
|
||||
|
||||
@@ -11802,6 +11802,7 @@ package android.telephony {
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
|
||||
@@ -11920,6 +11921,14 @@ package android.telephony {
|
||||
field public static final int RESULT_SUCCESS = 0; // 0x0
|
||||
}
|
||||
|
||||
public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception {
|
||||
method public int getErrorCode();
|
||||
field public static final int ERROR_INVALID_INFO_RECEIVED = 2; // 0x2
|
||||
field public static final int ERROR_MODEM_RESPONSE_ERROR = 3; // 0x3
|
||||
field public static final int ERROR_PHONE_NOT_AVAILABLE = 1; // 0x1
|
||||
field public static final int ERROR_UNKNOWN = 0; // 0x0
|
||||
}
|
||||
|
||||
public final class UiccAccessRule implements android.os.Parcelable {
|
||||
ctor public UiccAccessRule(byte[], @Nullable String, long);
|
||||
method public int describeContents();
|
||||
|
||||
@@ -1735,6 +1735,7 @@ package android.telephony {
|
||||
|
||||
public final class ModemActivityInfo implements android.os.Parcelable {
|
||||
ctor public ModemActivityInfo(long, int, int, @NonNull int[], int);
|
||||
method public boolean isEmpty();
|
||||
method public boolean isValid();
|
||||
}
|
||||
|
||||
|
||||
42
core/java/android/os/OutcomeReceiver.java
Normal file
42
core/java/android/os/OutcomeReceiver.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 android.os;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Callback interface intended for use when an asynchronous operation may result in a failure.
|
||||
*
|
||||
* This interface may be used in cases where an asynchronous API may complete either with a value
|
||||
* or with a {@link Throwable} that indicates an error.
|
||||
* @param <R> The type of the result that's being sent.
|
||||
* @param <E> The type of the {@link Throwable} that contains more information about the error.
|
||||
*/
|
||||
public interface OutcomeReceiver<R, E extends Throwable> {
|
||||
/**
|
||||
* Called when the asynchronous operation succeeds and delivers a result value.
|
||||
* @param result The value delivered by the asynchronous operation.
|
||||
*/
|
||||
void onResult(@NonNull R result);
|
||||
|
||||
/**
|
||||
* Called when the asynchronous operation fails. The mode of failure is indicated by the
|
||||
* {@link Throwable} passed as an argument to this method.
|
||||
* @param error A subclass of {@link Throwable} with more details about the error that occurred.
|
||||
*/
|
||||
default void onError(@NonNull E error) {}
|
||||
}
|
||||
@@ -35200,6 +35200,11 @@ package android.os {
|
||||
ctor public OperationCanceledException(String);
|
||||
}
|
||||
|
||||
public interface OutcomeReceiver<R, E extends java.lang.Throwable> {
|
||||
method public default void onError(@NonNull E);
|
||||
method public void onResult(@NonNull R);
|
||||
}
|
||||
|
||||
public final class Parcel {
|
||||
method public void appendFrom(android.os.Parcel, int, int);
|
||||
method @Nullable public android.os.IBinder[] createBinderArray();
|
||||
|
||||
@@ -10657,6 +10657,7 @@ package android.telephony {
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
|
||||
@@ -10775,6 +10776,14 @@ package android.telephony {
|
||||
field public static final int RESULT_SUCCESS = 0; // 0x0
|
||||
}
|
||||
|
||||
public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception {
|
||||
method public int getErrorCode();
|
||||
field public static final int ERROR_INVALID_INFO_RECEIVED = 2; // 0x2
|
||||
field public static final int ERROR_MODEM_RESPONSE_ERROR = 3; // 0x3
|
||||
field public static final int ERROR_PHONE_NOT_AVAILABLE = 1; // 0x1
|
||||
field public static final int ERROR_UNKNOWN = 0; // 0x0
|
||||
}
|
||||
|
||||
public final class UiccAccessRule implements android.os.Parcelable {
|
||||
ctor public UiccAccessRule(byte[], @Nullable String, long);
|
||||
method public int describeContents();
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.content.Context;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.Bundle;
|
||||
import android.os.OutcomeReceiver;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.os.ServiceManager;
|
||||
@@ -39,6 +40,7 @@ import com.android.internal.os.BatteryStatsImpl;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.internal.util.function.pooled.PooledLambda;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -405,7 +407,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
|
||||
// We will request data from external processes asynchronously, and wait on a timeout.
|
||||
SynchronousResultReceiver wifiReceiver = null;
|
||||
SynchronousResultReceiver bluetoothReceiver = null;
|
||||
SynchronousResultReceiver modemReceiver = null;
|
||||
CompletableFuture<ModemActivityInfo> modemFuture = CompletableFuture.completedFuture(null);
|
||||
boolean railUpdated = false;
|
||||
|
||||
if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
|
||||
@@ -460,8 +462,22 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
|
||||
}
|
||||
|
||||
if (mTelephony != null) {
|
||||
modemReceiver = new SynchronousResultReceiver("telephony");
|
||||
mTelephony.requestModemActivityInfo(modemReceiver);
|
||||
CompletableFuture<ModemActivityInfo> temp = new CompletableFuture<>();
|
||||
mTelephony.requestModemActivityInfo(Runnable::run,
|
||||
new OutcomeReceiver<ModemActivityInfo,
|
||||
TelephonyManager.ModemActivityInfoException>() {
|
||||
@Override
|
||||
public void onResult(ModemActivityInfo result) {
|
||||
temp.complete(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(TelephonyManager.ModemActivityInfoException e) {
|
||||
Slog.w(TAG, "error reading modem stats:" + e);
|
||||
temp.complete(null);
|
||||
}
|
||||
});
|
||||
modemFuture = temp;
|
||||
}
|
||||
if (!railUpdated) {
|
||||
synchronized (mStats) {
|
||||
@@ -472,7 +488,15 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
|
||||
|
||||
final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
|
||||
final BluetoothActivityEnergyInfo bluetoothInfo = awaitControllerInfo(bluetoothReceiver);
|
||||
final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
|
||||
ModemActivityInfo modemInfo = null;
|
||||
try {
|
||||
modemInfo = modemFuture.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
|
||||
TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException | InterruptedException e) {
|
||||
Slog.w(TAG, "timeout or interrupt reading modem stats: " + e);
|
||||
} catch (ExecutionException e) {
|
||||
Slog.w(TAG, "exception reading modem stats: " + e.getCause());
|
||||
}
|
||||
final long elapsedRealtime = SystemClock.elapsedRealtime();
|
||||
final long uptime = SystemClock.uptimeMillis();
|
||||
final long elapsedRealtimeUs = elapsedRealtime * 1000;
|
||||
@@ -523,11 +547,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
|
||||
}
|
||||
|
||||
if (modemInfo != null) {
|
||||
if (modemInfo.isValid()) {
|
||||
mStats.updateMobileRadioState(modemInfo, elapsedRealtime, uptime);
|
||||
} else {
|
||||
Slog.w(TAG, "modem info is invalid: " + modemInfo);
|
||||
}
|
||||
mStats.updateMobileRadioState(modemInfo, elapsedRealtime, uptime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1732,7 +1732,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
|
||||
public void noteModemControllerActivity(final ModemActivityInfo info) {
|
||||
enforceCallingPermission();
|
||||
|
||||
if (info == null || !info.isValid()) {
|
||||
if (info == null) {
|
||||
Slog.e(TAG, "invalid modem data given: " + info);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ import android.os.Environment;
|
||||
import android.os.IStoraged;
|
||||
import android.os.IThermalEventListener;
|
||||
import android.os.IThermalService;
|
||||
import android.os.OutcomeReceiver;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
@@ -167,6 +168,7 @@ import com.android.server.stats.pull.netstats.SubInfo;
|
||||
import com.android.server.storage.DiskStatsFileLogger;
|
||||
import com.android.server.storage.DiskStatsLoggingService;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import org.json.JSONArray;
|
||||
@@ -1624,9 +1626,34 @@ public class StatsPullAtomService extends SystemService {
|
||||
int pullModemActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
|
||||
mTelephony.requestModemActivityInfo(modemReceiver);
|
||||
final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
|
||||
CompletableFuture<ModemActivityInfo> modemFuture = new CompletableFuture<>();
|
||||
mTelephony.requestModemActivityInfo(Runnable::run,
|
||||
new OutcomeReceiver<ModemActivityInfo,
|
||||
TelephonyManager.ModemActivityInfoException>() {
|
||||
@Override
|
||||
public void onResult(ModemActivityInfo result) {
|
||||
modemFuture.complete(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(TelephonyManager.ModemActivityInfoException e) {
|
||||
Slog.w(TAG, "error reading modem stats:" + e);
|
||||
modemFuture.complete(null);
|
||||
}
|
||||
});
|
||||
|
||||
ModemActivityInfo modemInfo;
|
||||
try {
|
||||
modemInfo = modemFuture.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
|
||||
TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException | InterruptedException e) {
|
||||
Slog.w(TAG, "timeout or interrupt reading modem stats: " + e);
|
||||
return StatsManager.PULL_SKIP;
|
||||
} catch (ExecutionException e) {
|
||||
Slog.w(TAG, "exception reading modem stats: " + e.getCause());
|
||||
return StatsManager.PULL_SKIP;
|
||||
}
|
||||
|
||||
if (modemInfo == null) {
|
||||
return StatsManager.PULL_SKIP;
|
||||
}
|
||||
|
||||
@@ -764,6 +764,7 @@ package android.telephony {
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
|
||||
@@ -882,6 +883,14 @@ package android.telephony {
|
||||
field public static final int RESULT_SUCCESS = 0; // 0x0
|
||||
}
|
||||
|
||||
public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception {
|
||||
method public int getErrorCode();
|
||||
field public static final int ERROR_INVALID_INFO_RECEIVED = 2; // 0x2
|
||||
field public static final int ERROR_MODEM_RESPONSE_ERROR = 3; // 0x3
|
||||
field public static final int ERROR_PHONE_NOT_AVAILABLE = 1; // 0x1
|
||||
field public static final int ERROR_UNKNOWN = 0; // 0x0
|
||||
}
|
||||
|
||||
public final class UiccAccessRule implements android.os.Parcelable {
|
||||
ctor public UiccAccessRule(byte[], @Nullable String, long);
|
||||
method public int describeContents();
|
||||
|
||||
@@ -130,7 +130,7 @@ public final class ModemActivityInfo implements Parcelable {
|
||||
+ " mTimestamp=" + mTimestamp
|
||||
+ " mSleepTimeMs=" + mSleepTimeMs
|
||||
+ " mIdleTimeMs=" + mIdleTimeMs
|
||||
+ " mTxTimeMs[]=" + mTxTimeMs
|
||||
+ " mTxTimeMs[]=" + Arrays.toString(mTxTimeMs)
|
||||
+ " mRxTimeMs=" + mRxTimeMs
|
||||
+ "}";
|
||||
}
|
||||
@@ -319,8 +319,6 @@ public final class ModemActivityInfo implements Parcelable {
|
||||
*
|
||||
* @return {@code true} if this {@link ModemActivityInfo} record is valid,
|
||||
* {@code false} otherwise.
|
||||
* TODO: remove usages of this outside Telephony by always returning a valid (or null) result
|
||||
* from telephony.
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
@@ -331,7 +329,9 @@ public final class ModemActivityInfo implements Parcelable {
|
||||
&& (getReceiveTimeMillis() >= 0) && !isEmpty());
|
||||
}
|
||||
|
||||
private boolean isEmpty() {
|
||||
/** @hide */
|
||||
@TestApi
|
||||
public boolean isEmpty() {
|
||||
boolean isTxPowerEmpty = mTxTimeMs == null || mTxTimeMs.length == 0
|
||||
|| Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0);
|
||||
|
||||
|
||||
@@ -55,7 +55,9 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.OutcomeReceiver;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Parcelable;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
@@ -167,6 +169,9 @@ public class TelephonyManager {
|
||||
*/
|
||||
public static final String MODEM_ACTIVITY_RESULT_KEY = "controller_activity";
|
||||
|
||||
/** @hide */
|
||||
public static final String EXCEPTION_RESULT_KEY = "exception";
|
||||
|
||||
/**
|
||||
* The process name of the Phone app as well as many other apps that use this process name, such
|
||||
* as settings and vendor components.
|
||||
@@ -10364,26 +10369,149 @@ public class TelephonyManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests the modem activity info. The recipient will place the result
|
||||
* in `result`.
|
||||
* @param result The object on which the recipient will send the resulting
|
||||
* {@link android.telephony.ModemActivityInfo} object with key of
|
||||
* {@link #MODEM_ACTIVITY_RESULT_KEY}.
|
||||
* Exception that may be supplied to the callback provided in {@link #requestModemActivityInfo}.
|
||||
* @hide
|
||||
*/
|
||||
public void requestModemActivityInfo(@NonNull ResultReceiver result) {
|
||||
@SystemApi
|
||||
public static class ModemActivityInfoException extends Exception {
|
||||
/** Indicates that an unknown error occurred */
|
||||
public static final int ERROR_UNKNOWN = 0;
|
||||
|
||||
/**
|
||||
* Indicates that the modem or phone processes are not available (such as when the device
|
||||
* is in airplane mode).
|
||||
*/
|
||||
public static final int ERROR_PHONE_NOT_AVAILABLE = 1;
|
||||
|
||||
/**
|
||||
* Indicates that the modem supplied an invalid instance of {@link ModemActivityInfo}
|
||||
*/
|
||||
public static final int ERROR_INVALID_INFO_RECEIVED = 2;
|
||||
|
||||
/**
|
||||
* Indicates that the modem encountered an internal failure when processing the request
|
||||
* for activity info.
|
||||
*/
|
||||
public static final int ERROR_MODEM_RESPONSE_ERROR = 3;
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = {"ERROR_"},
|
||||
value = {
|
||||
ERROR_UNKNOWN,
|
||||
ERROR_PHONE_NOT_AVAILABLE,
|
||||
ERROR_INVALID_INFO_RECEIVED,
|
||||
ERROR_MODEM_RESPONSE_ERROR,
|
||||
})
|
||||
public @interface ModemActivityInfoError {}
|
||||
|
||||
private final int mErrorCode;
|
||||
|
||||
/** @hide */
|
||||
public ModemActivityInfoException(@ModemActivityInfoError int errorCode) {
|
||||
mErrorCode = errorCode;
|
||||
}
|
||||
|
||||
public @ModemActivityInfoError int getErrorCode() {
|
||||
return mErrorCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (mErrorCode) {
|
||||
case ERROR_UNKNOWN: return "ERROR_UNKNOWN";
|
||||
case ERROR_PHONE_NOT_AVAILABLE: return "ERROR_PHONE_NOT_AVAILABLE";
|
||||
case ERROR_INVALID_INFO_RECEIVED: return "ERROR_INVALID_INFO_RECEIVED";
|
||||
case ERROR_MODEM_RESPONSE_ERROR: return "ERROR_MODEM_RESPONSE_ERROR";
|
||||
default: return "UNDEFINED";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the current modem activity info.
|
||||
*
|
||||
* The provided instance of {@link ModemActivityInfo} represents the cumulative activity since
|
||||
* the last restart of the phone process.
|
||||
*
|
||||
* @param callback A callback object to which the result will be delivered. If there was an
|
||||
* error processing the request, {@link OutcomeReceiver#onError} will be called
|
||||
* with more details about the error.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
|
||||
public void requestModemActivityInfo(@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull OutcomeReceiver<ModemActivityInfo, ModemActivityInfoException> callback) {
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
|
||||
// Pass no handler into the receiver, since we're going to be trampolining the call to the
|
||||
// listener onto the provided executor.
|
||||
ResultReceiver wrapperResultReceiver = new ResultReceiver(null) {
|
||||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle data) {
|
||||
if (data == null) {
|
||||
Log.w(TAG, "requestModemActivityInfo: received null bundle");
|
||||
sendErrorToListener(ModemActivityInfoException.ERROR_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
data.setDefusable(true);
|
||||
if (data.containsKey(EXCEPTION_RESULT_KEY)) {
|
||||
int receivedErrorCode = data.getInt(EXCEPTION_RESULT_KEY);
|
||||
sendErrorToListener(receivedErrorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.containsKey(MODEM_ACTIVITY_RESULT_KEY)) {
|
||||
Log.w(TAG, "requestModemActivityInfo: Bundle did not contain expected key");
|
||||
sendErrorToListener(ModemActivityInfoException.ERROR_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
Parcelable receivedResult = data.getParcelable(MODEM_ACTIVITY_RESULT_KEY);
|
||||
if (!(receivedResult instanceof ModemActivityInfo)) {
|
||||
Log.w(TAG, "requestModemActivityInfo: Bundle contained something that wasn't "
|
||||
+ "a ModemActivityInfo.");
|
||||
sendErrorToListener(ModemActivityInfoException.ERROR_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
ModemActivityInfo modemActivityInfo = (ModemActivityInfo) receivedResult;
|
||||
if (!modemActivityInfo.isValid()) {
|
||||
Log.w(TAG, "requestModemActivityInfo: Received an invalid ModemActivityInfo");
|
||||
sendErrorToListener(ModemActivityInfoException.ERROR_INVALID_INFO_RECEIVED);
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "requestModemActivityInfo: Sending result to app: " + modemActivityInfo);
|
||||
sendResultToListener(modemActivityInfo);
|
||||
}
|
||||
|
||||
private void sendResultToListener(ModemActivityInfo info) {
|
||||
Binder.withCleanCallingIdentity(() ->
|
||||
executor.execute(() ->
|
||||
callback.onResult(info)));
|
||||
}
|
||||
|
||||
private void sendErrorToListener(int code) {
|
||||
ModemActivityInfoException e = new ModemActivityInfoException(code);
|
||||
Binder.withCleanCallingIdentity(() ->
|
||||
executor.execute(() ->
|
||||
callback.onError(e)));
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
ITelephony service = getITelephony();
|
||||
if (service != null) {
|
||||
service.requestModemActivityInfo(result);
|
||||
service.requestModemActivityInfo(wrapperResultReceiver);
|
||||
return;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error calling ITelephony#getModemActivityInfo", e);
|
||||
}
|
||||
result.send(0, null);
|
||||
executor.execute(() -> callback.onError(
|
||||
new ModemActivityInfoException(
|
||||
ModemActivityInfoException.ERROR_PHONE_NOT_AVAILABLE)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user