Merge "Enhance Cell Location Api."
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 8c8e725..1b1638a 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -29,6 +29,7 @@
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import android.telephony.CellInfo;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -107,6 +108,8 @@
 
     private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN;
 
+    private CellInfo mCellInfo = null;
+
     static final int PHONE_STATE_PERMISSION_MASK =
                 PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
                 PhoneStateListener.LISTEN_CALL_STATE |
@@ -236,6 +239,13 @@
                             remove(r.binder);
                         }
                     }
+                    if ((events & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
+                        try {
+                            r.callback.onCellInfoChanged(new CellInfo(mCellInfo));
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
                 }
             }
         } else {
@@ -325,6 +335,26 @@
         broadcastSignalStrengthChanged(signalStrength);
     }
 
+    public void notifyCellInfo(CellInfo cellInfo) {
+        if (!checkNotifyPermission("notifyCellInfo()")) {
+            return;
+        }
+
+        synchronized (mRecords) {
+            mCellInfo = cellInfo;
+            for (Record r : mRecords) {
+                if ((r.events & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
+                    try {
+                        r.callback.onCellInfoChanged(new CellInfo(cellInfo));
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
     public void notifyMessageWaitingChanged(boolean mwi) {
         if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
             return;
@@ -530,6 +560,7 @@
             pw.println("  mDataConnectionLinkProperties=" + mDataConnectionLinkProperties);
             pw.println("  mDataConnectionLinkCapabilities=" + mDataConnectionLinkCapabilities);
             pw.println("  mCellLocation=" + mCellLocation);
+            pw.println("  mCellInfo=" + mCellInfo);
             pw.println("registrations: count=" + recordCount);
             for (Record r : mRecords) {
                 pw.println("  " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events));
@@ -655,6 +686,12 @@
 
         }
 
+        if ((events & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
+
+        }
+
         if ((events & PHONE_STATE_PERMISSION_MASK) != 0) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_PHONE_STATE, null);
diff --git a/telephony/java/android/telephony/CdmaCellIdentity.java b/telephony/java/android/telephony/CdmaCellIdentity.java
new file mode 100644
index 0000000..5b8454f
--- /dev/null
+++ b/telephony/java/android/telephony/CdmaCellIdentity.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2008 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;
+
+/**
+ * CellIdentity is to represent a unique CDMA cell
+ *
+ * @hide pending API review
+ */
+public final class CdmaCellIdentity extends CellIdentity implements Parcelable {
+    // Network Id 0..65535
+    private final int mNetworkId;
+    // CDMA System Id 0..32767
+    private final int mSystemId;
+    // Base Station Id 0..65535
+    private final int mBasestationId;
+    /**
+     * Longitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
+     * It is represented in units of 0.25 seconds and ranges from -2592000
+     * to 2592000, both values inclusive (corresponding to a range of -180
+     * to +180 degrees).
+     */
+    private final int mLongitude;
+    /**
+     * Latitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
+     * It is represented in units of 0.25 seconds and ranges from -1296000
+     * to 1296000, both values inclusive (corresponding to a range of -90
+     * to +90 degrees).
+     */
+    private final int mLatitude;
+
+    /**
+     * public constructor
+     * @param nid Network Id 0..65535
+     * @param sid CDMA System Id 0..32767
+     * @param bid Base Station Id 0..65535
+     * @param lon Longitude is a decimal number ranges from -2592000
+     *        to 2592000
+     * @param lat Latitude is a decimal number ranges from -1296000
+     *        to 1296000
+     * @param attr is comma separated “key=value” attribute pairs.
+     */
+    public CdmaCellIdentity (int nid, int sid,
+            int bid, int lon, int lat, String attr) {
+        super(CELLID_TYPE_CDMA, attr);
+        mNetworkId = nid;
+        mSystemId = sid;
+        mBasestationId = bid;
+        mLongitude = lon;
+        mLatitude = lat;
+    }
+
+    private CdmaCellIdentity(Parcel in) {
+        super(in);
+        mNetworkId = in.readInt();
+        mSystemId = in.readInt();
+        mBasestationId = in.readInt();
+        mLongitude = in.readInt();
+        mLatitude = in.readInt();
+    }
+
+    CdmaCellIdentity(CdmaCellIdentity cid) {
+        super(cid);
+        mNetworkId = cid.mNetworkId;
+        mSystemId = cid.mSystemId;
+        mBasestationId = cid.mBasestationId;
+        mLongitude = cid.mLongitude;
+        mLatitude = cid.mLatitude;
+    }
+
+    /**
+     * @return Network Id 0..65535
+     */
+    public int getNetworkId() {
+        return mNetworkId;
+    }
+
+    /**
+     * @return System Id 0..32767
+     */
+    public int getSystemId() {
+        return mSystemId;
+    }
+
+    /**
+     * @return Base Station Id 0..65535
+     */
+    public int getBasestationId() {
+        return mBasestationId;
+    }
+
+    /**
+     * @return Base station longitude, which is a decimal number as
+     * specified in 3GPP2 C.S0005-A v6.0. It is represented in units
+     * of 0.25 seconds and ranges from -2592000 to 2592000, both
+     * values inclusive (corresponding to a range of -180
+     * to +180 degrees).
+     */
+    public int getLongitude() {
+        return mLongitude;
+    }
+
+    /**
+     * @return Base station
+     */
+    /**
+     * @return Base station latitude, which is a decimal number as
+     * specified in 3GPP2 C.S0005-A v6.0. It is represented in units
+     * of 0.25 seconds and ranges from -1296000 to 1296000, both
+     * values inclusive (corresponding to a range of -90
+     * to +90 degrees).
+     */
+    public int getLatitude() {
+        return mLatitude;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mNetworkId);
+        dest.writeInt(mSystemId);
+        dest.writeInt(mBasestationId);
+        dest.writeInt(mLongitude);
+        dest.writeInt(mLatitude);
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Creator<CdmaCellIdentity> CREATOR =
+            new Creator<CdmaCellIdentity>() {
+        @Override
+        public CdmaCellIdentity createFromParcel(Parcel in) {
+            return new CdmaCellIdentity(in);
+        }
+
+        @Override
+        public CdmaCellIdentity[] newArray(int size) {
+            return new CdmaCellIdentity[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
new file mode 100644
index 0000000..65c220f
--- /dev/null
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2008 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;
+
+/**
+ * CellIdentity is to represent ONE unique cell in the world
+ * it contains all levels of info to identity country, carrier, etc.
+ *
+ * @hide pending API review
+ */
+public abstract class CellIdentity implements Parcelable {
+
+    // Cell is a GSM Cell {@link GsmCellIdentity}
+    public static final int CELLID_TYPE_GSM = 1;
+    // Cell is a CMDA Cell {@link CdmaCellIdentity}
+    public static final int CELLID_TYPE_CDMA = 2;
+    // Cell is a LTE Cell {@link LteCellIdentity}
+    public static final int CELLID_TYPE_LTE = 3;
+
+    private int mCellIdType;
+    private String mCellIdAttributes;
+
+    protected CellIdentity(int type, String attr) {
+        this.mCellIdType = type;
+        this.mCellIdAttributes = new String(attr);
+    }
+
+    protected CellIdentity(Parcel in) {
+        this.mCellIdType = in.readInt();
+        this.mCellIdAttributes = new String(in.readString());
+    }
+
+    protected CellIdentity(CellIdentity cid) {
+        this.mCellIdType = cid.mCellIdType;
+        this.mCellIdAttributes = new String(cid.mCellIdAttributes);
+    }
+
+    /**
+     * @return Cell Identity type as one of CELLID_TYPE_XXXX
+     */
+    public int getCellIdType() {
+        return mCellIdType;
+    }
+
+
+    /**
+     * @return Cell identity attribute pairs
+     * Comma separated “key=value” pairs.
+     *   key := must must an single alpha-numeric word
+     *   value := “quoted value string”
+     *
+     * Current list of keys and values:
+     *   type = fixed | mobile
+     */
+    public String getCellIdAttributes() {
+        return mCellIdAttributes;
+    }
+
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mCellIdType);
+        dest.writeString(mCellIdAttributes);
+    }
+}
diff --git a/telephony/java/android/telephony/CellInfo.aidl b/telephony/java/android/telephony/CellInfo.aidl
new file mode 100644
index 0000000..8bbb0b4
--- /dev/null
+++ b/telephony/java/android/telephony/CellInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2007, 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 CellInfo;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
new file mode 100644
index 0000000..9bea30c
--- /dev/null
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2008 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;
+
+/**
+ * Represent one snapshot observation of one cell info
+ * which contains the time of observation.
+ *
+ * @hide Pending API review
+ */
+public final class CellInfo implements Parcelable {
+    // Type to distinguish where time stamp gets recorded.
+    public static final int CELL_INFO_TIMESTAMP_TYPE_UNKNOWN = 0;
+    public static final int CELL_INFO_TIMESTAMP_TYPE_ANTENNA = 1;
+    public static final int CELL_INFO_TIMESTAMP_TYPE_MODEM = 2;
+    public static final int CELL_INFO_TIMESTAMP_TYPE_OEM_RIL = 3;
+    public static final int CELL_INFO_TIMESTAMP_TYPE_JAVA_RIL = 4;
+
+    // Observation time stamped as type in nanoseconds since boot
+    private final long mTimeStamp;
+    // Where time stamp gets recorded.
+    // Value of CELL_INFO_TIMESTAMP_TYPE_XXXX
+    private final int mTimeStampType;
+
+    private final boolean mRegistered;
+
+    private final SignalStrength mStrength;
+    private final long mTimingAdvance;
+
+    private final int mCellIdentityType;
+    private final CellIdentity mCellIdentity;
+
+    /**
+     * Public constructor
+     * @param timeStampType is one of CELL_INFO_TIMESTAMP_TYPE_XXXX
+     * @param timeStamp is observation time in nanoseconds since boot
+     * @param timingAdv is observed timing advance
+     * @param registered is true when register to this cellIdentity
+     * @param strength is observed signal strength
+     * @param cellIdentity is observed mobile cell
+     */
+    public CellInfo(int timeStampType, long timeStamp, long timingAdv,
+            boolean registered, SignalStrength strength,
+            CellIdentity cellIdentity) {
+
+        if (timeStampType < CELL_INFO_TIMESTAMP_TYPE_UNKNOWN ||
+                timeStampType > CELL_INFO_TIMESTAMP_TYPE_JAVA_RIL) {
+            mTimeStampType = CELL_INFO_TIMESTAMP_TYPE_UNKNOWN;
+        } else {
+            mTimeStampType = timeStampType;
+        }
+
+        mRegistered = registered;
+        mTimeStamp = timeStamp;
+        mTimingAdvance = timingAdv;
+        mStrength = new SignalStrength(strength);
+
+        mCellIdentityType = cellIdentity.getCellIdType();
+        // TODO: make defense copy
+        mCellIdentity = cellIdentity;
+    }
+
+    public CellInfo(CellInfo ci) {
+        this.mTimeStampType = ci.mTimeStampType;
+        this.mRegistered = ci.mRegistered;
+        this.mTimeStamp = ci.mTimeStamp;
+        this.mTimingAdvance = ci.mTimingAdvance;
+        this.mCellIdentityType = ci.mCellIdentityType;
+        this.mStrength = new SignalStrength(ci.mStrength);
+        switch(mCellIdentityType) {
+            case CellIdentity.CELLID_TYPE_GSM:
+                mCellIdentity = new GsmCellIdentity((GsmCellIdentity)ci.mCellIdentity);
+                break;
+            default:
+                mCellIdentity = null;
+        }
+    }
+
+    private CellInfo(Parcel in) {
+        mTimeStampType = in.readInt();
+        mRegistered = (in.readInt() == 1) ? true : false;
+        mTimeStamp = in.readLong();
+        mTimingAdvance = in.readLong();
+        mCellIdentityType = in.readInt();
+        mStrength = SignalStrength.CREATOR.createFromParcel(in);
+        switch(mCellIdentityType) {
+            case CellIdentity.CELLID_TYPE_GSM:
+                mCellIdentity = GsmCellIdentity.CREATOR.createFromParcel(in);
+                break;
+            default:
+                mCellIdentity = null;
+        }
+    }
+
+    /**
+     * @return the observation time in nanoseconds since boot
+     */
+    public long getTimeStamp() {
+        return mTimeStamp;
+    }
+
+    /**
+     * @return Where time stamp gets recorded.
+     * one of CELL_INFO_TIMESTAMP_TYPE_XXXX
+     */
+    public int getTimeStampType() {
+        return mTimeStampType;
+    }
+
+    /**
+     * @return true when register to this cellIdentity
+     */
+    public boolean isRegistered() {
+        return mRegistered;
+    }
+
+    /**
+     * @return observed timing advance
+     */
+    public long getTimingAdvance() {
+        return mTimingAdvance;
+    }
+
+    /**
+     * @return observed signal strength
+     */
+    public SignalStrength getSignalStrength() {
+        // make a defense copy
+        return new SignalStrength(mStrength);
+    }
+
+    /**
+     * @return observed cell identity
+     */
+    public CellIdentity getCellIdentity() {
+        // TODO: make a defense copy
+        return mCellIdentity;
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append("TimeStampType: ");
+        switch(mTimeStampType) {
+            case 1:
+                sb.append("antenna");
+                break;
+            case 2:
+                sb.append("modem");
+                break;
+            case 3:
+                sb.append("oem_ril");
+                break;
+            case 4:
+                sb.append("java_ril");
+                break;
+            default:
+                sb.append("unknown");
+        }
+        sb.append(", TimeStamp: ").append(mTimeStamp).append(" ns");
+        sb.append(", Registered: ").append(mRegistered ? "YES" : "NO");
+        sb.append(", TimingAdvance: ").append(mTimingAdvance);
+        sb.append(", Strength : " + mStrength);
+        sb.append(", Cell Iden: " + mCellIdentity);
+
+        return sb.toString();
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mTimeStampType);
+        dest.writeInt(mRegistered ? 1 : 0);
+        dest.writeLong(mTimeStamp);
+        dest.writeLong(mTimingAdvance);
+        dest.writeInt(mCellIdentityType);
+        mStrength.writeToParcel(dest, flags);
+        mCellIdentity.writeToParcel(dest, flags);
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Creator<CellInfo> CREATOR =
+            new Creator<CellInfo>() {
+        @Override
+        public CellInfo createFromParcel(Parcel in) {
+            return new CellInfo(in);
+        }
+
+        @Override
+        public CellInfo[] newArray(int size) {
+            return new CellInfo[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/GsmCellIdentity.java b/telephony/java/android/telephony/GsmCellIdentity.java
new file mode 100644
index 0000000..159cb52
--- /dev/null
+++ b/telephony/java/android/telephony/GsmCellIdentity.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2008 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;
+
+/**
+ * CellIdentity to represent a unique GSM or UMTS cell
+ *
+ * @hide pending API review
+ */
+public final class GsmCellIdentity extends CellIdentity implements Parcelable {
+
+    // 3-digit Mobile Country Code, 0..999
+    private final int mMcc;
+    // 2 or 3-digit Mobile Network Code, 0..999
+    private final int mMnc;
+    // 16-bit Location Area Code, 0..65535
+    private final int mLac;
+    // 16-bit GSM Cell Identity described in TS 27.007, 0..65535
+    // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455
+    private final int mCid;
+    // 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511
+    private final int mPsc;
+
+    /**
+     * public constructor
+     * @param mcc 3-digit Mobile Country Code, 0..999
+     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+     * @param lac 16-bit Location Area Code, 0..65535
+     * @param cid 16-bit GSM Cell Identity or 28-bit UMTS Cell Identity
+     * @param psc 9-bit UMTS Primary Scrambling Code
+     * @param attr is comma separated “key=value” attribute pairs.
+     */
+    public GsmCellIdentity (int mcc, int mnc,
+            int lac, int cid, int psc, String attr) {
+        super(CELLID_TYPE_GSM, attr);
+        mMcc = mcc;
+        mMnc = mnc;
+        mLac = lac;
+        mCid = cid;
+        mPsc = psc;
+    }
+
+    private GsmCellIdentity(Parcel in) {
+        super(in);
+        mMcc = in.readInt();
+        mMnc = in.readInt();
+        mLac = in.readInt();
+        mCid = in.readInt();
+        mPsc = in.readInt();
+    }
+
+    GsmCellIdentity(GsmCellIdentity cid) {
+        super(cid);
+        mMcc = cid.mMcc;
+        mMnc = cid.mMnc;
+        mLac = cid.mLac;
+        mCid = cid.mCid;
+        mPsc = cid.mPsc;
+    }
+
+    /**
+     * @return 3-digit Mobile Country Code, 0..999
+     */
+    public int getMcc() {
+        return mMcc;
+    }
+
+    /**
+     * @return 2 or 3-digit Mobile Network Code, 0..999
+     */
+    public int getMnc() {
+        return mMnc;
+    }
+
+    /**
+     * @return 16-bit Location Area Code, 0..65535
+     */
+    public int getLac() {
+        return mLac;
+    }
+
+    /**
+     * @return CID
+     * Either 16-bit GSM Cell Identity described
+     * in TS 27.007, 0..65535
+     * or 28-bit UMTS Cell Identity described
+     * in TS 25.331, 0..268435455
+     */
+    public int getCid() {
+        return mCid;
+    }
+
+    /**
+     * @return 9-bit UMTS Primary Scrambling Code described in
+     * TS 25.331, 0..511
+     */
+    public int getPsc() {
+        return mPsc;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mMcc);
+        dest.writeInt(mMnc);
+        dest.writeInt(mLac);
+        dest.writeInt(mCid);
+        dest.writeInt(mPsc);
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Creator<GsmCellIdentity> CREATOR =
+            new Creator<GsmCellIdentity>() {
+        @Override
+        public GsmCellIdentity createFromParcel(Parcel in) {
+            return new GsmCellIdentity(in);
+        }
+
+        @Override
+        public GsmCellIdentity[] newArray(int size) {
+            return new GsmCellIdentity[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/LteCellIdentity.java b/telephony/java/android/telephony/LteCellIdentity.java
new file mode 100644
index 0000000..396922e
--- /dev/null
+++ b/telephony/java/android/telephony/LteCellIdentity.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2008 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;
+
+/**
+ * CellIdentity is to represent a unique LTE cell
+ *
+ * @hide pending API review
+ */
+public final class LteCellIdentity extends CellIdentity implements Parcelable {
+
+    // 3-digit Mobile Country Code, 0..999
+    private final int mMcc;
+    // 2 or 3-digit Mobile Network Code, 0..999
+    private final int mMnc;
+    // 28-bit cell identity
+    private final int mCi;
+    // physical cell id 0..503
+    private final int mPci;
+    // 16-bit tracking area code
+    private final int mTac;
+
+    /**
+     *
+     * @param mcc 3-digit Mobile Country Code, 0..999
+     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+     * @param ci 28-bit Cell Identity
+     * @param pci Physical Cell Id 0..503
+     * @param tac 16-bit Tracking Area Code
+     * @param attr is comma separated “key=value” attribute pairs.
+     */
+    public LteCellIdentity (int mcc, int mnc,
+            int ci, int pci, int tac, String attr) {
+        super(CELLID_TYPE_CDMA, attr);
+        mMcc = mcc;
+        mMnc = mnc;
+        mCi = ci;
+        mPci = pci;
+        mTac = tac;
+    }
+
+    private LteCellIdentity(Parcel in) {
+        super(in);
+        mMcc = in.readInt();
+        mMnc = in.readInt();
+        mCi = in.readInt();
+        mPci = in.readInt();
+        mTac = in.readInt();
+    }
+
+    LteCellIdentity(LteCellIdentity cid) {
+        super(cid);
+        mMcc = cid.mMcc;
+        mMnc = cid.mMnc;
+        mCi = cid.mCi;
+        mPci = cid.mPci;
+        mTac = cid.mTac;
+    }
+
+    /**
+     * @return 3-digit Mobile Country Code, 0..999
+     */
+    public int getMcc() {
+        return mMcc;
+    }
+
+    /**
+     * @return 2 or 3-digit Mobile Network Code, 0..999
+     */
+    public int getMnc() {
+        return mMnc;
+    }
+
+    /**
+     * @return 28-bit Cell Identity
+     */
+    public int getCi() {
+        return mCi;
+    }
+
+    /**
+     * @return Physical Cell Id 0..503
+     */
+    public int getPci() {
+        return mPci;
+    }
+
+    /**
+     * @return 16-bit Tracking Area Code
+     */
+    public int getTac() {
+        return mTac;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mMcc);
+        dest.writeInt(mMnc);
+        dest.writeInt(mCi);
+        dest.writeInt(mPci);
+        dest.writeInt(mTac);
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Creator<LteCellIdentity> CREATOR =
+            new Creator<LteCellIdentity>() {
+        @Override
+        public LteCellIdentity createFromParcel(Parcel in) {
+            return new LteCellIdentity(in);
+        }
+
+        @Override
+        public LteCellIdentity[] newArray(int size) {
+            return new LteCellIdentity[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/NeighboringCellInfo.aidl b/telephony/java/android/telephony/NeighboringCellInfo.aidl
index c464332..8588970 100644
--- a/telephony/java/android/telephony/NeighboringCellInfo.aidl
+++ b/telephony/java/android/telephony/NeighboringCellInfo.aidl
@@ -1,4 +1,4 @@
-/* //device/java/android/android/content/Intent.aidl
+/*
 **
 ** Copyright 2007, The Android Open Source Project
 **
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index eda9b71..698206c 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -22,6 +22,7 @@
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.CellLocation;
+import android.telephony.CellInfo;
 import android.util.Log;
 
 import com.android.internal.telephony.IPhoneStateListener;
@@ -156,6 +157,14 @@
      */
     public static final int LISTEN_OTASP_CHANGED                            = 0x00000200;
 
+    /**
+     * Listen for changes to observed cell info.
+     *
+     * @see #onCellInfoChanged
+     * @hide pending API review
+     */
+    public static final int LISTEN_CELL_INFO = 0x00000400;
+
     public PhoneStateListener() {
     }
 
@@ -276,6 +285,20 @@
     }
 
     /**
+     * Callback invoked when a observed cell info gets changed.
+     *
+     * A notification should be sent when:
+     *     1. a cell is newly-observed.
+     *     2. a observed cell is not visible.
+     *     3. any of the cell info of a observed cell has changed.
+     *
+     * @hide pending API review
+     */
+    public void onCellInfoChanged(CellInfo cellInfo) {
+        // default implementation empty
+    }
+
+    /**
      * The callback methods need to be called on the handler thread where
      * this object was created.  If the binder did that for us it'd be nice.
      */
@@ -323,6 +346,10 @@
         public void onOtaspChanged(int otaspMode) {
             Message.obtain(mHandler, LISTEN_OTASP_CHANGED, otaspMode, 0).sendToTarget();
         }
+
+        public void onCellInfoChanged(CellInfo cellInfo) {
+            Message.obtain(mHandler, LISTEN_CELL_INFO, 0, 0).sendToTarget();
+        }
     };
 
     Handler mHandler = new Handler() {
@@ -360,6 +387,8 @@
                 case LISTEN_OTASP_CHANGED:
                     PhoneStateListener.this.onOtaspChanged(msg.arg1);
                     break;
+                case LISTEN_CELL_INFO:
+                    PhoneStateListener.this.onCellInfoChanged((CellInfo)msg.obj);
             }
         }
     };
diff --git a/telephony/java/android/telephony/ServiceState.aidl b/telephony/java/android/telephony/ServiceState.aidl
index 8522889..830e2cbf 100644
--- a/telephony/java/android/telephony/ServiceState.aidl
+++ b/telephony/java/android/telephony/ServiceState.aidl
@@ -1,4 +1,4 @@
-/* //device/java/android/android/content/Intent.aidl
+/*
 **
 ** Copyright 2007, The Android Open Source Project
 **
diff --git a/telephony/java/android/telephony/SignalStrength.aidl b/telephony/java/android/telephony/SignalStrength.aidl
index c25411e..e988c5f 100644
--- a/telephony/java/android/telephony/SignalStrength.aidl
+++ b/telephony/java/android/telephony/SignalStrength.aidl
@@ -1,4 +1,4 @@
-/* //device/java/android/android/content/Intent.aidl
+/*
 **
 ** Copyright (C) 2009 Qualcomm Innovation Center, Inc.  All Rights Reserved.
 ** Copyright (C) 2009 The Android Open Source Project
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 1984926..bc50906 100755
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1141,4 +1141,24 @@
         return sContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_sms_capable);
     }
+
+    /**
+     * Returns all observed cell information of the device.
+     *
+     * @return List of CellInfo or null if info unavailable.
+     *
+     * <p>Requires Permission:
+     * (@link android.Manifest.permission#ACCESS_COARSE_UPDATES}
+     *
+     * @hide pending API review
+     */
+    public List<CellInfo> getAllCellInfo() {
+        try {
+            return getITelephony().getAllCellInfo();
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            return null;
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index f769157..eb78a53e 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -21,6 +21,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telephony.CellInfo;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.util.Log;
@@ -156,6 +157,14 @@
         }
     }
 
+    public void notifyCellInfo(Phone sender, CellInfo cellInfo) {
+        try {
+            mRegistry.notifyCellInfo(cellInfo);
+        } catch (RemoteException ex) {
+
+        }
+    }
+
     public void notifyOtaspChanged(Phone sender, int otaspMode) {
         try {
             mRegistry.notifyOtaspChanged(otaspMode);
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 082c097..d6a1edd 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -19,6 +19,7 @@
 import android.os.Bundle;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import android.telephony.CellInfo;
 
 oneway interface IPhoneStateListener {
     void onServiceStateChanged(in ServiceState serviceState);
@@ -33,5 +34,6 @@
     void onDataActivity(int direction);
     void onSignalStrengthsChanged(in SignalStrength signalStrength);
     void onOtaspChanged(in int otaspMode);
+    void onCellInfoChanged(in CellInfo cellInfo);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 19441cd..12a7286 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -19,6 +19,7 @@
 import android.os.Bundle;
 import java.util.List;
 import android.telephony.NeighboringCellInfo;
+import android.telephony.CellInfo;
 
 /**
  * Interface used to interact with the phone.  Mostly this is used by the
@@ -278,5 +279,10 @@
      * or {@link PHone#LTE_ON_CDMA_TRUE}
      */
     int getLteOnCdmaMode();
+
+    /**
+     * Returns the all observed cell information of the device.
+     */
+    List<CellInfo> getAllCellInfo();
 }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 1f19282..3c9a99b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -22,6 +22,7 @@
 import android.os.Bundle;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import android.telephony.CellInfo;
 import com.android.internal.telephony.IPhoneStateListener;
 
 interface ITelephonyRegistry {
@@ -39,4 +40,5 @@
     void notifyDataConnectionFailed(String reason, String apnType);
     void notifyCellLocation(in Bundle cellLocation);
     void notifyOtaspChanged(in int otaspMode);
+    void notifyCellInfo(in CellInfo cellInfo);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneNotifier.java b/telephony/java/com/android/internal/telephony/PhoneNotifier.java
index 28a8d22..1076870 100644
--- a/telephony/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/PhoneNotifier.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony;
 
+import android.telephony.CellInfo;
+
 /**
  * {@hide}
  */
@@ -42,4 +44,7 @@
     public void notifyDataActivity(Phone sender);
 
     public void notifyOtaspChanged(Phone sender, int otaspMode);
+
+    // TODO - trigger notifyCellInfo from ServiceStateTracker
+    public void notifyCellInfo(Phone sender, CellInfo cellInfo);
 }
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
index 7bbe696..cb67a93 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony;
 
 import com.android.internal.telephony.Phone;
+import android.telephony.CellInfo;
 
 /**
  * Stub class used for unit tests
@@ -59,4 +60,7 @@
 
     public void notifyOtaspChanged(Phone sender, int otaspMode) {
     }
+
+    public void notifyCellInfo(Phone sender, CellInfo cellInfo) {
+    }
 }