OSDN Git Service

Add API to support async network scans.
authoryinxu <yinxu@google.com>
Wed, 12 Apr 2017 23:09:54 +0000 (16:09 -0700)
committeryinxu <yinxu@google.com>
Fri, 12 May 2017 22:01:02 +0000 (15:01 -0700)
This CL includes the new Java API that supports async network scans.
Applications could get faster network scan results with this new API.
The long-term goal is to support Subsecond Switching which is separate
from what this CL is doing.

Bug: 30954762
Test: Unit test, run runtest -x NetworkScanRequestTest.java
Change-Id: I78cadaf838dee8439fe7417ef39f689990bf5705
(cherry picked from commit fdfb6f4d2f6db943d648adec6cc96530f2f70fe6)

telephony/java/android/telephony/NetworkScan.java [new file with mode: 0644]
telephony/java/android/telephony/NetworkScanRequest.aidl [new file with mode: 0644]
telephony/java/android/telephony/NetworkScanRequest.java [new file with mode: 0644]
telephony/java/android/telephony/RadioAccessSpecifier.aidl [new file with mode: 0644]
telephony/java/android/telephony/RadioAccessSpecifier.java [new file with mode: 0644]
telephony/java/android/telephony/RadioNetworkConstants.java [new file with mode: 0644]
telephony/java/android/telephony/TelephonyManager.java
telephony/java/android/telephony/TelephonyScanManager.java [new file with mode: 0644]
telephony/java/com/android/internal/telephony/ITelephony.aidl

diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
new file mode 100644 (file)
index 0000000..0cb4cff
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 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.telephony;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.internal.telephony.ITelephony;
+
+/**
+ * Allows applications to request the system to perform a network scan.
+ *
+ * The caller of {@link #requestNetworkScan(NetworkScanRequest, NetworkScanCallback)} will
+ * receive a NetworkScan which contains the callback method to stop the scan requested.
+ * @hide
+ */
+public class NetworkScan {
+
+    public static final String TAG = "NetworkScan";
+
+    public static final int SUCCESS = 0;
+    public static final int ERROR_INVALID_SCAN = 1;
+    public static final int ERROR_UNSUPPORTED = 2;
+    public static final int ERROR_INTERRUPTED = 3;
+    public static final int ERROR_CANCELLED = 4;
+
+    private final int mScanId;
+    private final int mSubId;
+
+    /**
+     * Stops the network scan
+     *
+     * This is the callback method to stop an ongoing scan. When user requests a new scan,
+     * a NetworkScan object will be returned, and the user can stop the scan by calling this
+     * method.
+     */
+    public void stop() throws RemoteException {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.stopNetworkScan(mSubId, mScanId);
+            } else {
+                throw new RemoteException("Failed to get the ITelephony instance.");
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "stopNetworkScan  RemoteException", ex);
+            throw new RemoteException("Failed to stop the network scan with id " + mScanId);
+        }
+    }
+
+    /**
+     * Creates a new NetworkScan with scanId
+     *
+     * @param scanId The id of the scan
+     * @param subId the id of the subscription
+     * @hide
+     */
+    public NetworkScan(int scanId, int subId) {
+        mScanId = scanId;
+        mSubId = subId;
+    }
+
+    private ITelephony getITelephony() {
+        return ITelephony.Stub.asInterface(
+            ServiceManager.getService(Context.TELEPHONY_SERVICE));
+    }
+}
diff --git a/telephony/java/android/telephony/NetworkScanRequest.aidl b/telephony/java/android/telephony/NetworkScanRequest.aidl
new file mode 100644 (file)
index 0000000..5addb1c
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017, 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.telephony;
+
+parcelable NetworkScanRequest;
diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java
new file mode 100644 (file)
index 0000000..0a542a7
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * Defines a request to peform a network scan.
+ *
+ * This class defines whether the network scan will be performed only once or periodically until
+ * cancelled, when the scan is performed periodically, the time interval is not controlled by the
+ * user but defined by the modem vendor.
+ * @hide
+ */
+public final class NetworkScanRequest implements Parcelable {
+
+    /** Performs the scan only once */
+    public static final int SCAN_TYPE_ONE_SHOT = 0;
+    /**
+     * Performs the scan periodically until cancelled
+     *
+     * The modem will start new scans periodically, and the interval between two scans is usually
+     * multiple minutes.
+     * */
+    public static final int SCAN_TYPE_PERIODIC = 1;
+
+    /** Defines the type of the scan. */
+    public int scanType;
+
+    /** Describes the radio access technologies with bands or channels that need to be scanned. */
+    public RadioAccessSpecifier[] specifiers;
+
+    /**
+     * Creates a new NetworkScanRequest with scanType and network specifiers
+     *
+     * @param scanType The type of the scan
+     * @param specifiers the radio network with bands / channels to be scanned
+     */
+    public NetworkScanRequest(int scanType, RadioAccessSpecifier[] specifiers) {
+        this.scanType = scanType;
+        this.specifiers = specifiers;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(scanType);
+        dest.writeParcelableArray(specifiers, flags);
+    }
+
+    private NetworkScanRequest(Parcel in) {
+        scanType = in.readInt();
+        specifiers = (RadioAccessSpecifier[]) in.readParcelableArray(
+                Object.class.getClassLoader(),
+                RadioAccessSpecifier.class);
+    }
+
+    @Override
+    public boolean equals (Object o) {
+        NetworkScanRequest nsr;
+
+        try {
+            nsr = (NetworkScanRequest) o;
+        } catch (ClassCastException ex) {
+            return false;
+        }
+
+        if (o == null) {
+            return false;
+        }
+
+        return (scanType == nsr.scanType
+                && Arrays.equals(specifiers, nsr.specifiers));
+    }
+
+    @Override
+    public int hashCode () {
+        return ((scanType * 31)
+                + (Arrays.hashCode(specifiers)) * 37);
+    }
+
+    public static final Creator<NetworkScanRequest> CREATOR =
+            new Creator<NetworkScanRequest>() {
+                @Override
+                public NetworkScanRequest createFromParcel(Parcel in) {
+                    return new NetworkScanRequest(in);
+                }
+
+                @Override
+                public NetworkScanRequest[] newArray(int size) {
+                    return new NetworkScanRequest[size];
+                }
+            };
+}
diff --git a/telephony/java/android/telephony/RadioAccessSpecifier.aidl b/telephony/java/android/telephony/RadioAccessSpecifier.aidl
new file mode 100644 (file)
index 0000000..7e09e0b
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017, 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.telephony;
+
+parcelable RadioAccessSpecifier;
diff --git a/telephony/java/android/telephony/RadioAccessSpecifier.java b/telephony/java/android/telephony/RadioAccessSpecifier.java
new file mode 100644 (file)
index 0000000..33ce8b4
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2017 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * Describes a particular radio access network to be scanned.
+ *
+ * The scan can be performed on either bands or channels for a specific radio access network type.
+ * @hide
+ */
+public final class RadioAccessSpecifier implements Parcelable {
+
+    /**
+     * The radio access network that needs to be scanned
+     *
+     * See {@link RadioNetworkConstants.RadioAccessNetworks} for details.
+     */
+    public int radioAccessNetwork;
+
+    /**
+     * The frequency bands that need to be scanned
+     *
+     * bands must be used together with radioAccessNetwork
+     *
+     * See {@link RadioNetworkConstants} for details.
+     */
+    public int[] bands;
+
+    /**
+     * The frequency channels that need to be scanned
+     *
+     * channels must be used together with radioAccessNetwork
+     *
+     * See {@link RadioNetworkConstants.RadioAccessNetworks} for details.
+     */
+    public int[] channels;
+
+    /**
+    * Creates a new RadioAccessSpecifier with radio network, bands and channels
+    *
+    * The user must specify the radio network type, and at least specify either of frequency
+    * bands or channels.
+    *
+    * @param ran The type of the radio access network
+    * @param bands the frequency bands to be scanned
+    * @param channels the frequency bands to be scanned
+    */
+    public RadioAccessSpecifier(int ran, int[] bands, int[] channels) {
+        this.radioAccessNetwork = ran;
+        this.bands = bands;
+        this.channels = channels;
+    }
+
+    public static final Parcelable.Creator<RadioAccessSpecifier> CREATOR =
+            new Parcelable.Creator<RadioAccessSpecifier> (){
+                @Override
+                public RadioAccessSpecifier createFromParcel(Parcel in) {
+                    return new RadioAccessSpecifier(in);
+                }
+
+                @Override
+                public RadioAccessSpecifier[] newArray(int size) {
+                    return new RadioAccessSpecifier[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(radioAccessNetwork);
+        dest.writeIntArray(bands);
+        dest.writeIntArray(channels);
+    }
+
+    private RadioAccessSpecifier(Parcel in) {
+        radioAccessNetwork = in.readInt();
+        bands = in.createIntArray();
+        channels = in.createIntArray();
+    }
+
+    @Override
+    public boolean equals (Object o) {
+        RadioAccessSpecifier ras;
+
+        try {
+            ras = (RadioAccessSpecifier) o;
+        } catch (ClassCastException ex) {
+            return false;
+        }
+
+        if (o == null) {
+            return false;
+        }
+
+        return (radioAccessNetwork == ras.radioAccessNetwork
+                && Arrays.equals(bands, ras.bands)
+                && Arrays.equals(channels, ras.channels));
+    }
+
+    @Override
+    public int hashCode () {
+        return ((radioAccessNetwork * 31)
+                + (Arrays.hashCode(bands) * 37)
+                + (Arrays.hashCode(channels)) * 39);
+    }
+}
diff --git a/telephony/java/android/telephony/RadioNetworkConstants.java b/telephony/java/android/telephony/RadioNetworkConstants.java
new file mode 100644 (file)
index 0000000..1a9072d
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2017 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.telephony;
+
+/**
+ * Contains radio access network related constants.
+ * @hide
+ */
+public final class RadioNetworkConstants {
+
+    public static final class RadioAccessNetworks {
+        public static final int GERAN = 1;
+        public static final int UTRAN = 2;
+        public static final int EUTRAN = 3;
+        /** @hide */
+        public static final int CDMA2000 = 4;
+    }
+
+    /**
+     * Frenquency bands for GERAN.
+     * http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf
+     */
+    public static final class GeranBands {
+        public static final int BAND_T380 = 1;
+        public static final int BAND_T410 = 2;
+        public static final int BAND_450 = 3;
+        public static final int BAND_480 = 4;
+        public static final int BAND_710 = 5;
+        public static final int BAND_750 = 6;
+        public static final int BAND_T810 = 7;
+        public static final int BAND_850 = 8;
+        public static final int BAND_P900 = 9;
+        public static final int BAND_E900 = 10;
+        public static final int BAND_R900 = 11;
+        public static final int BAND_DCS1800 = 12;
+        public static final int BAND_PCS1900 = 13;
+        public static final int BAND_ER900 = 14;
+    }
+
+    /**
+     * Frenquency bands for UTRAN.
+     * http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf
+     */
+    public static final class UtranBands {
+        public static final int BAND_1 = 1;
+        public static final int BAND_2 = 2;
+        public static final int BAND_3 = 3;
+        public static final int BAND_4 = 4;
+        public static final int BAND_5 = 5;
+        public static final int BAND_6 = 6;
+        public static final int BAND_7 = 7;
+        public static final int BAND_8 = 8;
+        public static final int BAND_9 = 9;
+        public static final int BAND_10 = 10;
+        public static final int BAND_11 = 11;
+        public static final int BAND_12 = 12;
+        public static final int BAND_13 = 13;
+        public static final int BAND_14 = 14;
+        /** band 15, 16, 17, 18 are reserved */
+        public static final int BAND_19 = 19;
+        public static final int BAND_20 = 20;
+        public static final int BAND_21 = 21;
+        public static final int BAND_22 = 22;
+        /** band 23, 24 are reserved */
+        public static final int BAND_25 = 25;
+        public static final int BAND_26 = 26;
+    }
+
+    /**
+     * Frenquency bands for EUTRAN.
+     * http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf
+     */
+    public static final class EutranBands {
+        public static final int BAND_1 = 1;
+        public static final int BAND_2 = 2;
+        public static final int BAND_3 = 3;
+        public static final int BAND_4 = 4;
+        public static final int BAND_5 = 5;
+        public static final int BAND_6 = 6;
+        public static final int BAND_7 = 7;
+        public static final int BAND_8 = 8;
+        public static final int BAND_9 = 9;
+        public static final int BAND_10 = 10;
+        public static final int BAND_11 = 11;
+        public static final int BAND_12 = 12;
+        public static final int BAND_13 = 13;
+        public static final int BAND_14 = 14;
+        public static final int BAND_17 = 17;
+        public static final int BAND_18 = 18;
+        public static final int BAND_19 = 19;
+        public static final int BAND_20 = 20;
+        public static final int BAND_21 = 21;
+        public static final int BAND_22 = 22;
+        public static final int BAND_23 = 23;
+        public static final int BAND_24 = 24;
+        public static final int BAND_25 = 25;
+        public static final int BAND_26 = 26;
+        public static final int BAND_27 = 27;
+        public static final int BAND_28 = 28;
+        public static final int BAND_30 = 30;
+        public static final int BAND_31 = 31;
+        public static final int BAND_33 = 33;
+        public static final int BAND_34 = 34;
+        public static final int BAND_35 = 35;
+        public static final int BAND_36 = 36;
+        public static final int BAND_37 = 37;
+        public static final int BAND_38 = 38;
+        public static final int BAND_39 = 39;
+        public static final int BAND_40 = 40;
+        public static final int BAND_41 = 41;
+        public static final int BAND_42 = 42;
+        public static final int BAND_43 = 43;
+        public static final int BAND_44 = 44;
+        public static final int BAND_45 = 45;
+        public static final int BAND_46 = 46;
+        public static final int BAND_47 = 47;
+        public static final int BAND_48 = 48;
+        public static final int BAND_65 = 65;
+        public static final int BAND_66 = 66;
+        public static final int BAND_68 = 68;
+        public static final int BAND_70 = 70;
+    }
+
+    /**
+     * Frenquency bands for CDMA2000.
+     * http://www.3gpp2.org/Public_html/Specs/C.S0057-E_v1.0_Bandclass_Specification.pdf
+     * @hide
+     *
+     * TODO(yinxu): Check with the nexus team about the definition of CDMA bands.
+     */
+    public static final class CdmaBands {
+        public static final int BAND_0 = 1;
+        public static final int BAND_1 = 2;
+        public static final int BAND_2 = 3;
+        public static final int BAND_3 = 4;
+        public static final int BAND_4 = 5;
+        public static final int BAND_5 = 6;
+        public static final int BAND_6 = 7;
+        public static final int BAND_7 = 8;
+        public static final int BAND_8 = 9;
+        public static final int BAND_9 = 10;
+        public static final int BAND_10 = 11;
+        public static final int BAND_11 = 12;
+        public static final int BAND_12 = 13;
+        public static final int BAND_13 = 14;
+        public static final int BAND_14 = 15;
+        public static final int BAND_15 = 16;
+        public static final int BAND_16 = 17;
+        public static final int BAND_17 = 18;
+        public static final int BAND_18 = 19;
+        public static final int BAND_19 = 20;
+        public static final int BAND_20 = 21;
+        public static final int BAND_21 = 22;
+    }
+}
index 32536fc..21db9f6 100644 (file)
@@ -39,6 +39,11 @@ import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcelable;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -144,6 +149,7 @@ public class TelephonyManager {
     private final Context mContext;
     private final int mSubId;
     private SubscriptionManager mSubscriptionManager;
+    private TelephonyScanManager mTelephonyScanManager;
 
     private static String multiSimConfig =
             SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
@@ -4573,6 +4579,32 @@ public class TelephonyManager {
     }
 
     /**
+     * Request a network scan.
+     *
+     * This method is asynchronous, so the network scan results will be returned by callback.
+     * The returned NetworkScan will contain a callback method which can be used to stop the scan.
+     *
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param request Contains all the RAT with bands/channels that need to be scanned.
+     * @param callback Returns network scan results or errors.
+     * @return A NetworkScan obj which contains a callback which can stop the scan.
+     * @hide
+     */
+    public NetworkScan requestNetworkScan(
+            NetworkScanRequest request, TelephonyScanManager.NetworkScanCallback callback) {
+        synchronized (this) {
+            if (mTelephonyScanManager == null) {
+                mTelephonyScanManager = new TelephonyScanManager();
+            }
+        }
+        return mTelephonyScanManager.requestNetworkScan(getSubId(), request, callback);
+    }
+
+    /**
      * Ask the radio to connect to the input network and change selection mode to manual.
      *
      * <p>
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
new file mode 100644 (file)
index 0000000..c905d3a
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2017 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.telephony;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.util.SparseArray;
+import java.util.List;
+
+import com.android.internal.telephony.ITelephony;
+
+/**
+ * Manages the radio access network scan requests and callbacks.
+ * @hide
+ */
+public final class TelephonyScanManager {
+
+    private static final String TAG = "TelephonyScanManager";
+
+    /** @hide */
+    public static final int CALLBACK_SCAN_RESULTS = 1;
+    /** @hide */
+    public static final int CALLBACK_SCAN_ERROR = 2;
+    /** @hide */
+    public static final int CALLBACK_SCAN_COMPLETE = 3;
+
+    /**
+     * The caller of {@link #requestNetworkScan(NetworkScanRequest, NetworkScanCallback)} should
+     * implement and provide this callback so that the scan results or errors can be returned.
+     */
+    public static abstract class NetworkScanCallback {
+        /** Returns the scan results to the user, this callback will be called multiple times. */
+        public void onResults(List<CellInfo> results) {}
+
+        /**
+         * Informs the user that the scan has stopped.
+         *
+         * This callback will be called when the scan is finished or cancelled by the user.
+         * The related NetworkScanRequest will be deleted after this callback.
+         */
+        public void onComplete() {}
+
+        /**
+         * Informs the user that there is some error about the scan.
+         *
+         * This callback will be called whenever there is any error about the scan, but the scan
+         * won't stop unless the onComplete() callback is called.
+         */
+        public void onError(int error) {}
+    }
+
+    private static class NetworkScanInfo {
+        private final NetworkScanRequest mRequest;
+        private final NetworkScanCallback mCallback;
+
+        NetworkScanInfo(NetworkScanRequest request, NetworkScanCallback callback) {
+            mRequest = request;
+            mCallback = callback;
+        }
+    }
+
+    private final Looper mLooper;
+    private final Messenger mMessenger;
+    private SparseArray<NetworkScanInfo> mScanInfo = new SparseArray<NetworkScanInfo>();
+
+    public TelephonyScanManager() {
+        HandlerThread thread = new HandlerThread(TAG);
+        thread.start();
+        mLooper = thread.getLooper();
+        mMessenger = new Messenger(new Handler(mLooper) {
+            @Override
+            public void handleMessage(Message message) {
+                checkNotNull(message, "message cannot be null");
+                NetworkScanInfo nsi;
+                synchronized (mScanInfo) {
+                    nsi = mScanInfo.get(message.arg2);
+                }
+                if (nsi == null) {
+                    throw new RuntimeException(
+                        "Failed to find NetworkScanInfo with id " + message.arg2);
+                }
+                NetworkScanCallback callback = nsi.mCallback;
+                if (callback == null) {
+                    throw new RuntimeException(
+                        "Failed to find NetworkScanCallback with id " + message.arg2);
+                }
+
+                switch (message.what) {
+                    case CALLBACK_SCAN_RESULTS:
+                        try {
+                            callback.onResults((List<CellInfo>) message.obj);
+                        } catch (Exception e) {
+                            Rlog.e(TAG, "Exception in networkscan callback onResults", e);
+                        }
+                        break;
+                    case CALLBACK_SCAN_ERROR:
+                        try {
+                            callback.onError(message.arg1);
+                        } catch (Exception e) {
+                            Rlog.e(TAG, "Exception in networkscan callback onError", e);
+                        }
+                        break;
+                    case CALLBACK_SCAN_COMPLETE:
+                        try {
+                            callback.onComplete();
+                            mScanInfo.remove(message.arg2);
+                        } catch (Exception e) {
+                            Rlog.e(TAG, "Exception in networkscan callback onComplete", e);
+                        }
+                        break;
+                    default:
+                        Rlog.e(TAG, "Unhandled message " + Integer.toHexString(message.what));
+                        break;
+                }
+            }
+        });
+    }
+
+    /**
+     * Request a network scan.
+     *
+     * This method is asynchronous, so the network scan results will be returned by callback.
+     * The returned NetworkScan will contain a callback method which can be used to stop the scan.
+     *
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param request Contains all the RAT with bands/channels that need to be scanned.
+     * @param callback Returns network scan results or errors.
+     * @return A NetworkScan obj which contains a callback which can stop the scan.
+     * @hide
+     */
+    public NetworkScan requestNetworkScan(int subId,
+            NetworkScanRequest request, NetworkScanCallback callback) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                int scanId = telephony.requestNetworkScan(subId, request, mMessenger, new Binder());
+                saveScanInfo(scanId, request, callback);
+                return new NetworkScan(scanId, subId);
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "requestNetworkScan RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "requestNetworkScan NPE", ex);
+        }
+        return null;
+    }
+
+    private void saveScanInfo(int id, NetworkScanRequest request, NetworkScanCallback callback) {
+        synchronized (mScanInfo) {
+            mScanInfo.put(id, new NetworkScanInfo(request, callback));
+        }
+    }
+
+    private ITelephony getITelephony() {
+        return ITelephony.Stub.asInterface(
+            ServiceManager.getService(Context.TELEPHONY_SERVICE));
+    }
+}
index f2e1e26..c8bc862 100644 (file)
@@ -19,6 +19,8 @@ package com.android.internal.telephony;
 import android.app.PendingIntent;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Messenger;
 import android.os.ResultReceiver;
 import android.net.Uri;
 import android.service.carrier.CarrierIdentifier;
@@ -29,6 +31,7 @@ import android.telephony.ClientRequestStats;
 import android.telephony.IccOpenLogicalChannelResponse;
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
+import android.telephony.NetworkScanRequest;
 import android.telephony.RadioAccessFamily;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyHistogram;
@@ -794,6 +797,26 @@ interface ITelephony {
     CellNetworkScanResult getCellNetworkScanResults(int subId);
 
     /**
+     * Perform a radio network scan and return the id of this scan.
+     *
+     * @param subId the id of the subscription.
+     * @param request Defines all the configs for network scan.
+     * @param messenger Callback messages will be sent using this messenger.
+     * @param binder the binder object instantiated in TelephonyManager.
+     * @return An id for this scan.
+     */
+    int requestNetworkScan(int subId, in NetworkScanRequest request, in Messenger messenger,
+            in IBinder binder);
+
+    /**
+     * Stop an existing radio network scan.
+     *
+     * @param subId the id of the subscription.
+     * @param scanId The id of the scan that is going to be stopped.
+     */
+    void stopNetworkScan(int subId, int scanId);
+
+    /**
      * Ask the radio to connect to the input network and change selection mode to manual.
      *
      * @param subId the id of the subscription.