Merge "Fix a bug in TaskStackBuilder where task stack PendingIntents would not clear tasks properly."
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index f7a7eb8..bb4b282 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -50,6 +50,8 @@
     public SpannableStringBuilder(CharSequence text, int start, int end) {
         int srclen = end - start;
 
+        if (srclen < 0) throw new StringIndexOutOfBoundsException();
+
         int len = ArrayUtils.idealCharArraySize(srclen + 1);
         mText = new char[len];
         mGapStart = srclen;
@@ -153,7 +155,7 @@
         if (where == mGapStart)
             return;
 
-        boolean atend = (where == length());
+        boolean atEnd = (where == length());
 
         if (where < mGapStart) {
             int overlap = mGapStart - where;
@@ -179,7 +181,7 @@
             else if (start == where) {
                 int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
 
-                if (flag == POINT || (atend && flag == PARAGRAPH))
+                if (flag == POINT || (atEnd && flag == PARAGRAPH))
                     start += mGapLength;
             }
 
@@ -190,7 +192,7 @@
             else if (end == where) {
                 int flag = (mSpanFlags[i] & END_MASK);
 
-                if (flag == POINT || (atend && flag == PARAGRAPH))
+                if (flag == POINT || (atEnd && flag == PARAGRAPH))
                     end += mGapLength;
             }
 
@@ -397,7 +399,7 @@
 
     // Documentation from interface
     public SpannableStringBuilder replace(final int start, final int end,
-                        CharSequence tb, int tbstart, int tbend) {
+            CharSequence tb, int tbstart, int tbend) {
         int filtercount = mFilters.length;
         for (int i = 0; i < filtercount; i++) {
             CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
@@ -419,53 +421,26 @@
         TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class);
         sendBeforeTextChanged(textWatchers, start, origLen, newLen);
 
-        if (origLen == 0 || newLen == 0) {
-            change(start, end, tb, tbstart, tbend);
-        } else {
-            int selstart = Selection.getSelectionStart(this);
-            int selend = Selection.getSelectionEnd(this);
+        // Try to keep the cursor / selection at the same relative position during
+        // a text replacement. If replaced or replacement text length is zero, this
+        // is already taken care of.
+        boolean adjustSelection = origLen != 0 && newLen != 0;
+        int selstart = 0;
+        int selend = 0;
+        if (adjustSelection) {
+            selstart = Selection.getSelectionStart(this);
+            selend = Selection.getSelectionEnd(this);
+        }
 
-            // XXX just make the span fixups in change() do the right thing
-            // instead of this madness!
+        checkRange("replace", start, end);
 
-            checkRange("replace", start, end);
-            moveGapTo(end);
+        change(start, end, tb, tbstart, tbend);
 
-            if (mGapLength < 2)
-                resizeFor(length() + 1);
-
-            for (int i = mSpanCount - 1; i >= 0; i--) {
-                if (mSpanStarts[i] == mGapStart)
-                    mSpanStarts[i]++;
-
-                if (mSpanEnds[i] == mGapStart)
-                    mSpanEnds[i]++;
-            }
-
-            mText[mGapStart] = ' ';
-            mGapStart++;
-            mGapLength--;
-
-            if (mGapLength < 1) {
-                new Exception("mGapLength < 1").printStackTrace();
-            }
-
-            change(start + 1, start + 1, tb, tbstart, tbend);
-            change(start, start + 1, "", 0, 0);
-            change(start + newLen, start + newLen + origLen, "", 0, 0);
-
-            /*
-             * Special case to keep the cursor in the same position
-             * if it was somewhere in the middle of the replaced region.
-             * If it was at the start or the end or crossing the whole
-             * replacement, it should already be where it belongs.
-             * TODO: Is there some more general mechanism that could
-             * accomplish this?
-             */
+        if (adjustSelection) {
             if (selstart > start && selstart < end) {
                 long off = selstart - start;
 
-                off = off * newLen / (end - start);
+                off = off * newLen / origLen;
                 selstart = (int) off + start;
 
                 setSpan(false, Selection.SELECTION_START, selstart, selstart,
@@ -474,7 +449,7 @@
             if (selend > start && selend < end) {
                 long off = selend - start;
 
-                off = off * newLen / (end - start);
+                off = off * newLen / origLen;
                 selend = (int) off + start;
 
                 setSpan(false, Selection.SELECTION_END, selend, selend, Spanned.SPAN_POINT_POINT);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5d7c8cd..3c4b866 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4059,14 +4059,7 @@
     void ensureInputFocusOnFirstFocusable() {
         View root = getRootView();
         if (root != null) {
-            // Find the first focusble from the top.
-            View next = root.focusSearch(FOCUS_FORWARD);
-            if (next != null) {
-                // Giving focus to the found focusable will not
-                // perform a search since we found a view that is
-                // guaranteed to be able to take focus.
-                next.requestFocus(FOCUS_FORWARD);
-            }
+            root.requestFocus(FOCUS_FORWARD);
         }
     }
 
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_search_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_search_activated.png
new file mode 100644
index 0000000..0d2e2ef
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_search_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_search_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_search_normal.png
new file mode 100644
index 0000000..66d14ae
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_search_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_search_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_search_activated.png
new file mode 100644
index 0000000..73c6be6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_search_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_search_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_search_normal.png
new file mode 100644
index 0000000..73c6be6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_search_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_search_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_search_activated.png
new file mode 100644
index 0000000..c625a36
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_search_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_search_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_search_normal.png
new file mode 100644
index 0000000..c625a36
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_search_normal.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lockscreen_search.xml b/core/res/res/drawable/ic_lockscreen_search.xml
new file mode 100644
index 0000000..b103922
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_search.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_search_normal" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_search_activated" />
+
+</selector>
diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml
index 68e5cfd..537d27c 100644
--- a/core/res/res/values-land/arrays.xml
+++ b/core/res/res/values-land/arrays.xml
@@ -23,49 +23,49 @@
     <array name="lockscreen_targets_when_silent">
         <item>@null</item>"
         <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@null</item>
+        <item>@drawable/ic_lockscreen_search</item>
         <item>@drawable/ic_lockscreen_soundon</item>
     </array>
 
     <array name="lockscreen_target_descriptions_when_silent">
         <item>@null</item>
         <item>@string/description_target_unlock</item>
-        <item>@null</item>
+        <item>@string/description_target_search</item>
         <item>@string/description_target_soundon</item>
     </array>
 
     <array name="lockscreen_direction_descriptions">
         <item>@null</item>
         <item>@string/description_direction_up</item>
-        <item>@null</item>
+        <item>@string/description_direction_left</item>
         <item>@string/description_direction_down</item>
     </array>
 
     <array name="lockscreen_targets_when_soundon">
         <item>@null</item>
         <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@null</item>
+        <item>@drawable/ic_lockscreen_search</item>
         <item>@drawable/ic_lockscreen_silent</item>
     </array>
 
     <array name="lockscreen_target_descriptions_when_soundon">
         <item>@null</item>
         <item>@string/description_target_unlock</item>
-        <item>@null</item>
+        <item>@string/description_target_search</item>
         <item>@string/description_target_silent</item>
     </array>
 
     <array name="lockscreen_targets_with_camera">
         <item>@null</item>
         <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@null</item>
+        <item>@drawable/ic_lockscreen_search</item>
         <item>@drawable/ic_lockscreen_camera</item>
     </array>
 
     <array name="lockscreen_target_descriptions_with_camera">
         <item>@null</item>
         <item>@string/description_target_unlock</item>
-        <item>@null</item>
+        <item>@string/description_target_search</item>
         <item>@string/description_target_camera</item>
     </array>
 
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 90ddc4b..d05a31c 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -353,49 +353,49 @@
     <!-- Resources for MultiWaveView in LockScreen -->
     <array name="lockscreen_targets_when_silent">
         <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@null</item>
+        <item>@drawable/ic_lockscreen_search</item>
         <item>@drawable/ic_lockscreen_soundon</item>
         <item>@null</item>
     </array>
 
     <array name="lockscreen_target_descriptions_when_silent">
         <item>@string/description_target_unlock</item>
-        <item>@null</item>
+        <item>@string/description_target_search</item>
         <item>@string/description_target_soundon</item>
         <item>@null</item>
     </array>
 
     <array name="lockscreen_direction_descriptions">
         <item>@string/description_direction_right</item>
-        <item>@null</item>
+        <item>@string/description_direction_up</item>
         <item>@string/description_direction_left</item>
         <item>@null</item>
     </array>
 
     <array name="lockscreen_targets_when_soundon">
         <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@null</item>
+        <item>@drawable/ic_lockscreen_search</item>
         <item>@drawable/ic_lockscreen_silent</item>
         <item>@null</item>
     </array>
 
     <array name="lockscreen_target_descriptions_when_soundon">
         <item>@string/description_target_unlock</item>
-        <item>@null</item>
+        <item>@string/description_target_search</item>
         <item>@string/description_target_silent</item>
         <item>@null</item>
     </array>
 
     <array name="lockscreen_targets_with_camera">
         <item>@drawable/ic_lockscreen_unlock</item>
-        <item>@null</item>
+        <item>@drawable/ic_lockscreen_search</item>
         <item>@drawable/ic_lockscreen_camera</item>
         <item>@null</item>
     </array>
 
     <array name="lockscreen_target_descriptions_with_camera">
         <item>@string/description_target_unlock</item>
-        <item>@null</item>
+        <item>@string/description_target_search</item>
         <item>@string/description_target_camera</item>
         <item>@null</item>
     </array>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 516078f..195c2e1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -992,6 +992,7 @@
   <java-symbol type="drawable" name="ic_lockscreen_camera" />
   <java-symbol type="drawable" name="ic_lockscreen_silent" />
   <java-symbol type="drawable" name="ic_lockscreen_unlock" />
+  <java-symbol type="drawable" name="ic_lockscreen_search" />
 
   <java-symbol type="layout" name="action_bar_home" />
   <java-symbol type="layout" name="action_bar_title_item" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 718de0a..44f2ade 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3303,6 +3303,8 @@
     <string name="description_target_silent">Silent</string>
     <!-- Description of the sound on target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
     <string name="description_target_soundon">Sound on</string>
+    <!-- Description of the unlock target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
+    <string name="description_target_search">Search</string>
 
     <!-- Description of the unlock handle in the Slide unlock screen for tablets. [CHAR LIMIT=NONE] -->
     <string name="description_target_unlock_tablet">Swipe to unlock.</string>
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index c9a130b..e8ba21d 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -17,10 +17,8 @@
 package com.android.internal.policy.impl;
 
 import com.android.internal.R;
-import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallback;
 import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallbackImpl;
 import com.android.internal.policy.impl.KeyguardUpdateMonitor.SimStateCallback;
-import com.android.internal.policy.impl.LockScreen.MultiWaveViewMethods;
 import com.android.internal.telephony.IccCard.State;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.SlidingTab;
@@ -29,6 +27,7 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.SearchManager;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
@@ -39,6 +38,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.*;
+import android.speech.RecognizerIntent;
 import android.util.Log;
 import android.media.AudioManager;
 import android.os.RemoteException;
@@ -79,7 +79,8 @@
     private KeyguardStatusViewManager mStatusViewManager;
     private UnlockWidgetCommonMethods mUnlockWidgetMethods;
     private View mUnlockWidget;
-    public boolean mCameraDisabled;
+    private boolean mCameraDisabled;
+    private boolean mSearchDisabled;
 
     InfoCallbackImpl mInfoCallback = new InfoCallbackImpl() {
 
@@ -94,14 +95,14 @@
 
         @Override
         public void onDevicePolicyManagerStateChanged() {
-            updateCameraTarget();
+            updateTargets();
         }
 
     };
 
     SimStateCallback mSimStateCallback = new SimStateCallback() {
         public void onSimStateChanged(State simState) {
-            updateCameraTarget();
+            updateTargets();
         }
     };
 
@@ -243,11 +244,12 @@
 
         MultiWaveViewMethods(MultiWaveView multiWaveView) {
             mMultiWaveView = multiWaveView;
+
+            // TODO: get search icon.  See Launcher.updateGlobalSearchIcon()
         }
 
-        public boolean isCameraTargetPresent() {
-            return mMultiWaveView
-                .getTargetPosition(com.android.internal.R.drawable.ic_lockscreen_camera) != -1;
+        public boolean isTargetPresent(int resId) {
+            return mMultiWaveView.getTargetPosition(resId) != -1;
         }
 
         public void updateResources() {
@@ -263,6 +265,7 @@
                 mMultiWaveView.setTargetResources(resId);
             }
             setEnabled(com.android.internal.R.drawable.ic_lockscreen_camera, !mCameraDisabled);
+            setEnabled(com.android.internal.R.drawable.ic_lockscreen_search, !mSearchDisabled);
         }
 
         public void onGrabbed(View v, int handle) {
@@ -276,8 +279,13 @@
         public void onTrigger(View v, int target) {
             final int resId = mMultiWaveView.getResourceIdForTarget(target);
             switch (resId) {
+                case com.android.internal.R.drawable.ic_lockscreen_search:
+                    launchActivity(new Intent(RecognizerIntent.ACTION_WEB_SEARCH));
+                    mCallback.pokeWakelock();
+                    break;
+
                 case com.android.internal.R.drawable.ic_lockscreen_camera:
-                    launchCamera();
+                    launchActivity(new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA));
                     mCallback.pokeWakelock();
                     break;
 
@@ -292,8 +300,7 @@
             }
         }
 
-        private void launchCamera() {
-            Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+        private void launchActivity(Intent intent) {
             intent.setFlags(
                     Intent.FLAG_ACTIVITY_NEW_TASK
                     | Intent.FLAG_ACTIVITY_SINGLE_TOP
@@ -457,18 +464,29 @@
         }
     }
 
-    private void updateCameraTarget() {
+    private void updateTargets() {
         boolean disabledByAdmin = mLockPatternUtils.getDevicePolicyManager()
                 .getCameraDisabled(null);
         boolean disabledBySimState = mUpdateMonitor.isSimLocked();
-        boolean targetPresent = (mUnlockWidgetMethods instanceof MultiWaveViewMethods)
-                ? ((MultiWaveViewMethods) mUnlockWidgetMethods).isCameraTargetPresent() : false;
+        boolean cameraTargetPresent = (mUnlockWidgetMethods instanceof MultiWaveViewMethods)
+                ? ((MultiWaveViewMethods) mUnlockWidgetMethods)
+                        .isTargetPresent(com.android.internal.R.drawable.ic_lockscreen_camera)
+                        : false;
+        boolean searchTargetPresent = (mUnlockWidgetMethods instanceof MultiWaveViewMethods)
+                ? ((MultiWaveViewMethods) mUnlockWidgetMethods)
+                        .isTargetPresent(com.android.internal.R.drawable.ic_lockscreen_search)
+                        : false;
+
+        // TODO: test to see if search is available
+        boolean searchActionAvailable = true;
+
         if (disabledByAdmin) {
             Log.v(TAG, "Camera disabled by Device Policy");
         } else if (disabledBySimState) {
             Log.v(TAG, "Camera disabled by Sim State");
         }
-        mCameraDisabled = disabledByAdmin || disabledBySimState || !targetPresent;
+        mCameraDisabled = disabledByAdmin || disabledBySimState || !cameraTargetPresent;
+        mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent;
         mUnlockWidgetMethods.updateResources();
     }
 
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) {
+    }
 }