Merge "In DRT2, correctly handle the case of zero tests"
diff --git a/Android.mk b/Android.mk
index b8a48a4..4a994ed 100644
--- a/Android.mk
+++ b/Android.mk
@@ -71,6 +71,7 @@
core/java/android/app/IBackupAgent.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
core/java/android/app/INotificationManager.aidl \
+ core/java/android/app/IProcessObserver.aidl \
core/java/android/app/ISearchManager.aidl \
core/java/android/app/ISearchManagerCallback.aidl \
core/java/android/app/IServiceConnection.aidl \
diff --git a/api/current.txt b/api/current.txt
index dd619cf..cf6e955 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -866,6 +866,7 @@
field public static final int subtitleTextStyle = 16843513; // 0x10102f9
field public static final int suggestActionMsg = 16843228; // 0x10101dc
field public static final int suggestActionMsgColumn = 16843229; // 0x10101dd
+ field public static final int suggestionsEnabled = 16843630; // 0x101036e
field public static final int summary = 16843241; // 0x10101e9
field public static final int summaryColumn = 16843426; // 0x10102a2
field public static final int summaryOff = 16843248; // 0x10101f0
@@ -13924,12 +13925,14 @@
public class ParcelFileDescriptor implements android.os.Parcelable {
ctor public ParcelFileDescriptor(android.os.ParcelFileDescriptor);
+ method public static android.os.ParcelFileDescriptor adoptFd(int);
method public void close() throws java.io.IOException;
method public static android.os.ParcelFileDescriptor[] createPipe() throws java.io.IOException;
method public int describeContents();
method public int detachFd();
method public static android.os.ParcelFileDescriptor dup(java.io.FileDescriptor) throws java.io.IOException;
method public static android.os.ParcelFileDescriptor fromDatagramSocket(java.net.DatagramSocket);
+ method public static android.os.ParcelFileDescriptor fromFd(int) throws java.io.IOException;
method public static android.os.ParcelFileDescriptor fromSocket(java.net.Socket);
method public int getFd();
method public java.io.FileDescriptor getFileDescriptor();
@@ -25205,6 +25208,7 @@
method public final android.content.res.ColorStateList getLinkTextColors();
method public final boolean getLinksClickable();
method public final android.text.method.MovementMethod getMovementMethod();
+ method public int getOffsetForPosition(float, float);
method public android.text.TextPaint getPaint();
method public int getPaintFlags();
method public java.lang.String getPrivateImeOptions();
@@ -25225,6 +25229,7 @@
method public android.text.style.URLSpan[] getUrls();
method public boolean hasSelection();
method public boolean isInputMethodTarget();
+ method public boolean isSuggestionsEnabled();
method public boolean isTextSelectable();
method public int length();
method public boolean moveCursorToVisibleOffset();
@@ -25296,6 +25301,7 @@
method public void setSingleLine();
method public void setSingleLine(boolean);
method public final void setSpannableFactory(android.text.Spannable.Factory);
+ method public void setSuggestionsEnabled(boolean);
method public final void setText(java.lang.CharSequence);
method public void setText(java.lang.CharSequence, android.widget.TextView.BufferType);
method public final void setText(char[], int, int);
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f2c97964..2a0d798 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1467,6 +1467,22 @@
return true;
}
+ case REGISTER_PROCESS_OBSERVER_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IProcessObserver observer = IProcessObserver.Stub.asInterface(
+ data.readStrongBinder());
+ registerProcessObserver(observer);
+ return true;
+ }
+
+ case UNREGISTER_PROCESS_OBSERVER_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IProcessObserver observer = IProcessObserver.Stub.asInterface(
+ data.readStrongBinder());
+ unregisterProcessObserver(observer);
+ return true;
+ }
+
}
return super.onTransact(code, data, reply, flags);
@@ -3300,5 +3316,27 @@
return result;
}
+ public void registerProcessObserver(IProcessObserver observer) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(observer != null ? observer.asBinder() : null);
+ mRemote.transact(REGISTER_PROCESS_OBSERVER_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(observer != null ? observer.asBinder() : null);
+ mRemote.transact(UNREGISTER_PROCESS_OBSERVER_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 54c3422..1f53c0e 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -355,6 +355,9 @@
public boolean removeTask(int taskId, int flags) throws RemoteException;
+ public void registerProcessObserver(IProcessObserver observer) throws RemoteException;
+ public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -577,4 +580,6 @@
int SWITCH_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+127;
int REMOVE_SUB_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+128;
int REMOVE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+129;
+ int REGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+130;
+ int UNREGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+131;
}
diff --git a/core/java/android/app/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl
new file mode 100644
index 0000000..2094294
--- /dev/null
+++ b/core/java/android/app/IProcessObserver.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 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.app;
+
+/** {@hide} */
+oneway interface IProcessObserver {
+
+ void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities);
+ void onProcessDied(int pid, int uid);
+
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 4c7d87f..a660bd7 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1544,6 +1544,9 @@
*/
public static final String NETWORKMANAGEMENT_SERVICE = "network_management";
+ /** {@hide} */
+ public static final String NETWORK_POLICY_SERVICE = "netpolicy";
+
/**
* Use with {@link #getSystemService} to retrieve a {@link
* android.net.wifi.WifiManager} for handling management of
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index fa6eae5..d9351ee 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -23,9 +23,6 @@
*/
interface INetworkPolicyManager {
- void onForegroundActivitiesChanged(int uid, int pid, boolean foregroundActivities);
- void onProcessDied(int uid, int pid);
-
void setUidPolicy(int uid, int policy);
int getUidPolicy(int uid);
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 2312bd9..1913aa7 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -16,6 +16,7 @@
package android.net;
+import android.content.Context;
import android.os.RemoteException;
/**
@@ -43,6 +44,10 @@
mService = service;
}
+ public static NetworkPolicyManager getSystemService(Context context) {
+ return (NetworkPolicyManager) context.getSystemService(Context.NETWORK_POLICY_SERVICE);
+ }
+
/**
* Set policy flags for specific UID.
*
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 4430e00..0f207bc 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -36,6 +36,9 @@
/** {@link #uid} value when entry is summarized over all UIDs. */
public static final int UID_ALL = 0;
+ // NOTE: data should only be accounted for once in this structure; if data
+ // is broken out, the summarized version should not be included.
+
/**
* {@link SystemClock#elapsedRealtime()} timestamp when this data was
* generated.
@@ -81,12 +84,13 @@
mTx = new long[size];
}
- public void addEntry(String iface, int uid, long rx, long tx) {
+ public Builder addEntry(String iface, int uid, long rx, long tx) {
mIface[mIndex] = iface;
mUid[mIndex] = uid;
mRx[mIndex] = rx;
mTx[mIndex] = tx;
mIndex++;
+ return this;
}
public NetworkStats build() {
@@ -97,11 +101,17 @@
}
}
+ public int length() {
+ // length is identical for all fields
+ return iface.length;
+ }
+
/**
* Find first stats index that matches the requested parameters.
*/
public int findIndex(String iface, int uid) {
- for (int i = 0; i < this.iface.length; i++) {
+ final int length = length();
+ for (int i = 0; i < length; i++) {
if (equal(iface, this.iface[i]) && uid == this.uid[i]) {
return i;
}
@@ -109,13 +119,38 @@
return -1;
}
- private static boolean equal(Object a, Object b) {
- return a == b || (a != null && a.equals(b));
+ /**
+ * Subtract the given {@link NetworkStats}, effectively leaving the delta
+ * between two snapshots in time. Assumes that statistics rows collect over
+ * time, and that none of them have disappeared.
+ */
+ public NetworkStats subtract(NetworkStats value) {
+ // result will have our rows, but no meaningful timestamp
+ final int length = length();
+ final NetworkStats.Builder result = new NetworkStats.Builder(-1, length);
+
+ for (int i = 0; i < length; i++) {
+ final String iface = this.iface[i];
+ final int uid = this.uid[i];
+
+ // find remote row that matches, and subtract
+ final int j = value.findIndex(iface, uid);
+ if (j == -1) {
+ // newly appearing row, return entire value
+ result.addEntry(iface, uid, this.rx[i], this.tx[i]);
+ } else {
+ // existing row, subtract remote value
+ final long rx = this.rx[i] - value.rx[j];
+ final long tx = this.tx[i] - value.tx[j];
+ result.addEntry(iface, uid, rx, tx);
+ }
+ }
+
+ return result.build();
}
- /** {@inheritDoc} */
- public int describeContents() {
- return 0;
+ private static boolean equal(Object a, Object b) {
+ return a == b || (a != null && a.equals(b));
}
public void dump(String prefix, PrintWriter pw) {
@@ -138,6 +173,11 @@
}
/** {@inheritDoc} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(elapsedRealtime);
dest.writeStringArray(iface);
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 7ee7a81..c0ff734 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -16,6 +16,12 @@
package android.net;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
import dalvik.system.BlockGuard;
import java.net.Socket;
@@ -36,6 +42,17 @@
public final static int UNSUPPORTED = -1;
/**
+ * Snapshot of {@link NetworkStats} when the currently active profiling
+ * session started, or {@code null} if no session active.
+ *
+ * @see #startDataProfiling(Context)
+ * @see #stopDataProfiling(Context)
+ */
+ private static NetworkStats sActiveProfilingStart;
+
+ private static Object sProfilingLock = new Object();
+
+ /**
* Set active tag to use when accounting {@link Socket} traffic originating
* from the current thread. Only one active tag per thread is supported.
* <p>
@@ -93,6 +110,44 @@
}
/**
+ * Start profiling data usage for current UID. Only one profiling session
+ * can be active at a time.
+ *
+ * @hide
+ */
+ public static void startDataProfiling(Context context) {
+ synchronized (sProfilingLock) {
+ if (sActiveProfilingStart != null) {
+ throw new IllegalStateException("already profiling data");
+ }
+
+ // take snapshot in time; we calculate delta later
+ sActiveProfilingStart = getNetworkStatsForUid(context);
+ }
+ }
+
+ /**
+ * Stop profiling data usage for current UID.
+ *
+ * @return Detailed {@link NetworkStats} of data that occurred since last
+ * {@link #startDataProfiling(Context)} call.
+ * @hide
+ */
+ public static NetworkStats stopDataProfiling(Context context) {
+ synchronized (sProfilingLock) {
+ if (sActiveProfilingStart == null) {
+ throw new IllegalStateException("not profiling data");
+ }
+
+ // subtract starting values and return delta
+ final NetworkStats profilingStop = getNetworkStatsForUid(context);
+ final NetworkStats profilingDelta = profilingStop.subtract(sActiveProfilingStart);
+ sActiveProfilingStart = null;
+ return profilingDelta;
+ }
+ }
+
+ /**
* Get the total number of packets transmitted through the mobile interface.
*
* @return number of packets. If the statistics are not supported by this device,
@@ -350,4 +405,21 @@
* {@link #UNSUPPORTED} will be returned.
*/
public static native long getUidUdpRxPackets(int uid);
+
+ /**
+ * Return detailed {@link NetworkStats} for the current UID. Requires no
+ * special permission.
+ */
+ private static NetworkStats getNetworkStatsForUid(Context context) {
+ final IBinder binder = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ final INetworkManagementService service = INetworkManagementService.Stub.asInterface(
+ binder);
+
+ final int uid = android.os.Process.myUid();
+ try {
+ return service.getNetworkStatsUidDetail(uid);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index ecc111b..f17a6f2 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -214,6 +214,12 @@
NetworkStats getNetworkStatsDetail();
/**
+ * Return detailed network statistics for the requested UID,
+ * including interface and tag details.
+ */
+ NetworkStats getNetworkStatsUidDetail(int uid);
+
+ /**
* Configures bandwidth throttling on an interface.
*/
void setInterfaceThrottle(String iface, int rxKbps, int txKbps);
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 727fcca..3ea3f56 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -129,7 +129,46 @@
}
/**
- * Create a new ParcelFileDescriptor from the specified Socket.
+ * Create a new ParcelFileDescriptor from a raw native fd. The new
+ * ParcelFileDescriptor holds a dup of the original fd passed in here,
+ * so you must still close that fd as well as the new ParcelFileDescriptor.
+ *
+ * @param fd The native fd that the ParcelFileDescriptor should dup.
+ *
+ * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
+ * for a dup of the given fd.
+ */
+ public static ParcelFileDescriptor fromFd(int fd) throws IOException {
+ FileDescriptor fdesc = getFileDescriptorFromFd(fd);
+ return new ParcelFileDescriptor(fdesc);
+ }
+
+ // Extracts the file descriptor from the specified socket and returns it untouched
+ private static native FileDescriptor getFileDescriptorFromFd(int fd) throws IOException;
+
+ /**
+ * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
+ * The returned ParcelFileDescriptor now owns the given fd, and will be
+ * responsible for closing it. You must not close the fd yourself.
+ *
+ * @param fd The native fd that the ParcelFileDescriptor should adopt.
+ *
+ * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
+ * for the given fd.
+ */
+ public static ParcelFileDescriptor adoptFd(int fd) {
+ FileDescriptor fdesc = getFileDescriptorFromFdNoDup(fd);
+ return new ParcelFileDescriptor(fdesc);
+ }
+
+ // Extracts the file descriptor from the specified socket and returns it untouched
+ private static native FileDescriptor getFileDescriptorFromFdNoDup(int fd);
+
+ /**
+ * Create a new ParcelFileDescriptor from the specified Socket. The new
+ * ParcelFileDescriptor holds a dup of the original FileDescriptor in
+ * the Socket, so you must still close the Socket as well as the new
+ * ParcelFileDescriptor.
*
* @param socket The Socket whose FileDescriptor is used to create
* a new ParcelFileDescriptor.
@@ -163,17 +202,14 @@
*/
public static ParcelFileDescriptor[] createPipe() throws IOException {
FileDescriptor[] fds = new FileDescriptor[2];
- int res = createPipeNative(fds);
- if (res == 0) {
- ParcelFileDescriptor[] pfds = new ParcelFileDescriptor[2];
- pfds[0] = new ParcelFileDescriptor(fds[0]);
- pfds[1] = new ParcelFileDescriptor(fds[1]);
- return pfds;
- }
- throw new IOException("Unable to create pipe: errno=" + -res);
+ createPipeNative(fds);
+ ParcelFileDescriptor[] pfds = new ParcelFileDescriptor[2];
+ pfds[0] = new ParcelFileDescriptor(fds[0]);
+ pfds[1] = new ParcelFileDescriptor(fds[1]);
+ return pfds;
}
- private static native int createPipeNative(FileDescriptor[] outFds);
+ private static native void createPipeNative(FileDescriptor[] outFds) throws IOException;
/**
* @hide Please use createPipe() or ContentProvider.openPipeHelper().
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 1375a29..01c640a 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1481,6 +1481,13 @@
onVmPolicyViolation(message, originStack);
}
+ /**
+ * @hide
+ */
+ public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) {
+ onVmPolicyViolation(null, originStack);
+ }
+
// Map from VM violation fingerprint to uptime millis.
private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index d432dee..fe96565 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -234,7 +234,7 @@
if (action == MotionEvent.ACTION_DOWN) {
boolean cap = isSelecting(buffer);
if (cap) {
- int offset = widget.getOffset((int) event.getX(), (int) event.getY());
+ int offset = widget.getOffsetForPosition(event.getX(), event.getY());
buffer.setSpan(LAST_TAP_DOWN, offset, offset, Spannable.SPAN_POINT_POINT);
@@ -259,7 +259,7 @@
// Update selection as we're moving the selection area.
// Get the current touch position
- int offset = widget.getOffset((int) event.getX(), (int) event.getY());
+ int offset = widget.getOffsetForPosition(event.getX(), event.getY());
Selection.extendSelection(buffer, offset);
return true;
@@ -275,7 +275,7 @@
return true;
}
- int offset = widget.getOffset((int) event.getX(), (int) event.getY());
+ int offset = widget.getOffsetForPosition(event.getX(), event.getY());
if (isSelecting(buffer)) {
buffer.removeSpan(LAST_TAP_DOWN);
Selection.extendSelection(buffer, offset);
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index 976e786..12391df 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -39,9 +39,6 @@
// immediately.
private boolean mHasInstantTimer;
- // Reference count the pause/resume of timers
- private int mPauseTimerRefCount;
-
private boolean mTimerPaused;
private boolean mHasDeferredTimers;
@@ -136,7 +133,7 @@
* Pause all timers.
*/
public void pause() {
- if (--mPauseTimerRefCount == 0) {
+ if (!mTimerPaused) {
mTimerPaused = true;
mHasDeferredTimers = false;
}
@@ -146,7 +143,7 @@
* Resume all timers.
*/
public void resume() {
- if (++mPauseTimerRefCount == 1) {
+ if (mTimerPaused) {
mTimerPaused = false;
if (mHasDeferredTimers) {
mHasDeferredTimers = false;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f774803..61a69ca 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -54,7 +54,9 @@
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
+import android.os.StrictMode;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
import android.text.Selection;
@@ -8933,15 +8935,14 @@
}
private static void checkThread() {
- if (!"main".equals(Thread.currentThread().getName())) {
- try {
- throw new RuntimeException("A WebView method was called on thread '" +
- Thread.currentThread().getName() + "'. " +
- "All WebView methods must be called on the UI thread. " +
- "Future versions of WebView may not support use on other threads.");
- } catch (RuntimeException e) {
- Log.e(LOGTAG, Log.getStackTraceString(e));
- }
+ if (Looper.myLooper() != Looper.getMainLooper()) {
+ RuntimeException exception = new RuntimeException(
+ "A WebView method was called on thread '" +
+ Thread.currentThread().getName() + "'. " +
+ "All WebView methods must be called on the UI thread. " +
+ "Future versions of WebView may not support use on other threads.");
+ Log.e(LOGTAG, Log.getStackTraceString(exception));
+ StrictMode.onWebViewMethodCalledOnWrongThread(exception);
}
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 1e1a043..563fc26 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1171,8 +1171,7 @@
int bottomEdge = displayFrame.bottom;
if (ignoreBottomDecorations) {
Resources res = anchor.getContext().getResources();
- bottomEdge = res.getDisplayMetrics().heightPixels -
- (int) res.getDimension(com.android.internal.R.dimen.screen_margin_bottom);
+ bottomEdge = res.getDisplayMetrics().heightPixels;
}
final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d58c72b..3875765 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -16,11 +16,6 @@
package android.widget;
-import com.android.internal.util.FastMath;
-import com.android.internal.widget.EditableInputConnection;
-
-import org.xmlpull.v1.XmlPullParserException;
-
import android.R;
import android.content.ClipData;
import android.content.ClipData.Item;
@@ -129,6 +124,11 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.util.FastMath;
+import com.android.internal.widget.EditableInputConnection;
+
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.BreakIterator;
@@ -320,6 +320,7 @@
private int mTextEditSuggestionItemLayout;
private SuggestionsPopupWindow mSuggestionsPopupWindow;
private SuggestionRangeSpan mSuggestionRangeSpan;
+ private boolean mSuggestionsEnabled = true;
private int mCursorDrawableRes;
private final Drawable[] mCursorDrawable = new Drawable[2];
@@ -329,7 +330,7 @@
private Drawable mSelectHandleRight;
private Drawable mSelectHandleCenter;
- private int mLastDownPositionX, mLastDownPositionY;
+ private float mLastDownPositionX, mLastDownPositionY;
private Callback mCustomSelectionActionModeCallback;
private final int mSquaredTouchSlopDistance;
@@ -806,6 +807,10 @@
case com.android.internal.R.styleable.TextView_textIsSelectable:
mTextIsSelectable = a.getBoolean(attr, false);
break;
+
+ case com.android.internal.R.styleable.TextView_suggestionsEnabled:
+ mSuggestionsEnabled = a.getBoolean(attr, true);
+ break;
}
}
a.recycle();
@@ -2898,8 +2903,7 @@
setText(mCharWrapper, mBufferType, false, oldlen);
}
- private static class CharWrapper
- implements CharSequence, GetChars, GraphicsOperations {
+ private static class CharWrapper implements CharSequence, GetChars, GraphicsOperations {
private char[] mChars;
private int mStart, mLength;
@@ -7323,8 +7327,8 @@
}
if (action == MotionEvent.ACTION_DOWN) {
- mLastDownPositionX = (int) event.getX();
- mLastDownPositionY = (int) event.getY();
+ mLastDownPositionX = event.getX();
+ mLastDownPositionY = event.getY();
// Reset this state; it will be re-set if super.onTouchEvent
// causes focus to move to the view.
@@ -7758,16 +7762,6 @@
hasPrimaryClip());
}
- private boolean isWordCharacter(int c, int type) {
- return (c == '\'' || c == '"' ||
- type == Character.UPPERCASE_LETTER ||
- type == Character.LOWERCASE_LETTER ||
- type == Character.TITLECASE_LETTER ||
- type == Character.MODIFIER_LETTER ||
- type == Character.OTHER_LETTER || // Should handle asian characters
- type == Character.DECIMAL_DIGIT_NUMBER);
- }
-
private static long packRangeInLong(int start, int end) {
return (((long) start) << 32) | end;
}
@@ -8140,7 +8134,7 @@
// Long press in empty space moves cursor and shows the Paste affordance if available.
if (!isPositionOnText(mLastDownPositionX, mLastDownPositionY) &&
mInsertionControllerEnabled) {
- final int offset = getOffset(mLastDownPositionX, mLastDownPositionY);
+ final int offset = getOffsetForPosition(mLastDownPositionX, mLastDownPositionY);
stopSelectionActionMode();
Selection.setSelection((Spannable) mText, offset);
getInsertionController().showWithPaste();
@@ -8208,7 +8202,7 @@
private final ViewGroup[] mSuggestionViews = new ViewGroup[2];
private final int[] mSuggestionViewLayouts = new int[] {
mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout};
- private WordIterator mWordIterator;
+ private WordIterator mSuggestionWordIterator;
private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan[0];
public SuggestionsPopupWindow() {
@@ -8344,26 +8338,27 @@
}
private long[] getWordLimits(CharSequence text) {
- if (mWordIterator == null) mWordIterator = new WordIterator(); // TODO locale
- mWordIterator.setCharSequence(text);
+ // TODO locale for mSuggestionWordIterator
+ if (mSuggestionWordIterator == null) mSuggestionWordIterator = new WordIterator();
+ mSuggestionWordIterator.setCharSequence(text);
// First pass will simply count the number of words to be able to create an array
// Not too expensive since previous break positions are cached by the BreakIterator
int nbWords = 0;
- int position = mWordIterator.following(0);
+ int position = mSuggestionWordIterator.following(0);
while (position != BreakIterator.DONE) {
nbWords++;
- position = mWordIterator.following(position);
+ position = mSuggestionWordIterator.following(position);
}
int index = 0;
long[] result = new long[nbWords];
- position = mWordIterator.following(0);
+ position = mSuggestionWordIterator.following(0);
while (position != BreakIterator.DONE) {
- int wordStart = mWordIterator.getBeginning(position);
+ int wordStart = mSuggestionWordIterator.getBeginning(position);
result[index++] = packRangeInLong(wordStart, position);
- position = mWordIterator.following(position);
+ position = mSuggestionWordIterator.following(position);
}
return result;
@@ -8601,6 +8596,8 @@
}
void showSuggestions() {
+ if (!mSuggestionsEnabled || !isTextEditable()) return;
+
if (mSuggestionsPopupWindow == null) {
mSuggestionsPopupWindow = new SuggestionsPopupWindow();
}
@@ -8615,6 +8612,31 @@
}
/**
+ * Some parts of the text can have alternate suggestion text attached. This is typically done by
+ * the IME by adding {@link SuggestionSpan}s to the text.
+ *
+ * When suggestions are enabled (default), this list of suggestions will be displayed when the
+ * user double taps on these parts of the text. No suggestions are displayed when this value is
+ * false. Use {@link #setSuggestionsEnabled(boolean)} to change this value.
+ *
+ * @return true if the suggestions popup window is enabled.
+ *
+ * @attr ref android.R.styleable#TextView_suggestionsEnabled
+ */
+ public boolean isSuggestionsEnabled() {
+ return mSuggestionsEnabled;
+ }
+
+ /**
+ * Enables or disables the suggestion popup. See {@link #isSuggestionsEnabled()}.
+ *
+ * @param enabled Whether or not suggestions are enabled.
+ */
+ public void setSuggestionsEnabled(boolean enabled) {
+ mSuggestionsEnabled = enabled;
+ }
+
+ /**
* If provided, this ActionMode.Callback will be used to create the ActionMode when text
* selection is initiated in this View.
*
@@ -9115,7 +9137,7 @@
public abstract void updateOffset(int offset);
- public abstract void updatePosition(int x, int y);
+ public abstract void updatePosition(float x, float y);
protected void positionAtCursorOffset(int offset) {
addPositionToTouchUpFilter(offset);
@@ -9215,7 +9237,7 @@
final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
final float newPosY = rawY - mTouchToWindowOffsetY + mTouchOffsetY;
- updatePosition(Math.round(newPosX), Math.round(newPosY));
+ updatePosition(newPosX, newPosY);
break;
}
@@ -9366,8 +9388,8 @@
}
@Override
- public void updatePosition(int x, int y) {
- updateOffset(getOffset(x, y));
+ public void updatePosition(float x, float y) {
+ updateOffset(getOffsetForPosition(x, y));
}
void showPastePopupWindow() {
@@ -9421,11 +9443,11 @@
}
@Override
- public void updatePosition(int x, int y) {
+ public void updatePosition(float x, float y) {
final int selectionStart = getSelectionStart();
final int selectionEnd = getSelectionEnd();
- int offset = getOffset(x, y);
+ int offset = getOffsetForPosition(x, y);
// No need to redraw when the offset is unchanged
if (offset == selectionStart) return;
@@ -9458,11 +9480,11 @@
}
@Override
- public void updatePosition(int x, int y) {
+ public void updatePosition(float x, float y) {
final int selectionStart = getSelectionStart();
final int selectionEnd = getSelectionEnd();
- int offset = getOffset(x, y);
+ int offset = getOffsetForPosition(x, y);
// No need to redraw when the offset is unchanged
if (offset == selectionEnd) return;
@@ -9560,7 +9582,7 @@
// Double tap detection
private long mPreviousTapUpTime = 0;
- private int mPreviousTapPositionX, mPreviousTapPositionY;
+ private float mPreviousTapPositionX, mPreviousTapPositionY;
SelectionModifierCursorController() {
resetTouchOffsets();
@@ -9593,19 +9615,19 @@
if (isTextEditable() || mTextIsSelectable) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
- final int x = (int) event.getX();
- final int y = (int) event.getY();
+ final float x = event.getX();
+ final float y = event.getY();
// Remember finger down position, to be able to start selection from there
- mMinTouchOffset = mMaxTouchOffset = getOffset(x, y);
+ mMinTouchOffset = mMaxTouchOffset = getOffsetForPosition(x, y);
// Double tap detection
long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime;
if (duration <= ViewConfiguration.getDoubleTapTimeout() &&
isPositionOnText(x, y)) {
- final int deltaX = x - mPreviousTapPositionX;
- final int deltaY = y - mPreviousTapPositionY;
- final int distanceSquared = deltaX * deltaX + deltaY * deltaY;
+ final float deltaX = x - mPreviousTapPositionX;
+ final float deltaY = y - mPreviousTapPositionY;
+ final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
if (distanceSquared < mSquaredTouchSlopDistance) {
showSuggestions();
mDiscardNextActionUp = true;
@@ -9641,9 +9663,7 @@
private void updateMinAndMaxOffsets(MotionEvent event) {
int pointerCount = event.getPointerCount();
for (int index = 0; index < pointerCount; index++) {
- final int x = (int) event.getX(index);
- final int y = (int) event.getY(index);
- int offset = getOffset(x, y);
+ int offset = getOffsetForPosition(event.getX(index), event.getY(index));
if (offset < mMinTouchOffset) mMinTouchOffset = offset;
if (offset > mMaxTouchOffset) mMaxTouchOffset = offset;
}
@@ -9701,41 +9721,40 @@
}
/**
- * Get the offset character closest to the specified absolute position.
+ * Get the character offset closest to the specified absolute position. A typical use case is to
+ * pass the result of {@link MotionEvent#getX()} and {@link MotionEvent#getY()} to this method.
*
* @param x The horizontal absolute position of a point on screen
* @param y The vertical absolute position of a point on screen
* @return the character offset for the character whose position is closest to the specified
* position. Returns -1 if there is no layout.
- *
- * @hide
*/
- public int getOffset(int x, int y) {
+ public int getOffsetForPosition(float x, float y) {
if (getLayout() == null) return -1;
final int line = getLineAtCoordinate(y);
final int offset = getOffsetAtCoordinate(line, x);
return offset;
}
- private int convertToLocalHorizontalCoordinate(int x) {
+ private float convertToLocalHorizontalCoordinate(float x) {
x -= getTotalPaddingLeft();
// Clamp the position to inside of the view.
- x = Math.max(0, x);
+ x = Math.max(0.0f, x);
x = Math.min(getWidth() - getTotalPaddingRight() - 1, x);
x += getScrollX();
return x;
}
- private int getLineAtCoordinate(int y) {
+ private int getLineAtCoordinate(float y) {
y -= getTotalPaddingTop();
// Clamp the position to inside of the view.
- y = Math.max(0, y);
+ y = Math.max(0.0f, y);
y = Math.min(getHeight() - getTotalPaddingBottom() - 1, y);
y += getScrollY();
- return getLayout().getLineForVertical(y);
+ return getLayout().getLineForVertical((int) y);
}
- private int getOffsetAtCoordinate(int line, int x) {
+ private int getOffsetAtCoordinate(int line, float x) {
x = convertToLocalHorizontalCoordinate(x);
return getLayout().getOffsetForHorizontal(line, x);
}
@@ -9743,7 +9762,7 @@
/** Returns true if the screen coordinates position (x,y) corresponds to a character displayed
* in the view. Returns false when the position is in the empty space of left/right of text.
*/
- private boolean isPositionOnText(int x, int y) {
+ private boolean isPositionOnText(float x, float y) {
if (getLayout() == null) return false;
final int line = getLineAtCoordinate(y);
@@ -9765,7 +9784,7 @@
return true;
case DragEvent.ACTION_DRAG_LOCATION:
- final int offset = getOffset((int) event.getX(), (int) event.getY());
+ final int offset = getOffsetForPosition(event.getX(), event.getY());
Selection.setSelection((Spannable)mText, offset);
return true;
@@ -9789,7 +9808,7 @@
content.append(item.coerceToText(TextView.this.mContext));
}
- final int offset = getOffset((int) event.getX(), (int) event.getY());
+ final int offset = getOffsetForPosition(event.getX(), event.getY());
Object localState = event.getLocalState();
DragLocalState dragLocalState = null;
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 290bf08..7b4f216 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -89,7 +89,6 @@
final int childCount = getChildCount();
final int midVertical = (top + bottom) / 2;
final int dividerWidth = getDividerWidth();
- boolean hasOverflow = false;
int overflowWidth = 0;
int nonOverflowWidth = 0;
int nonOverflowCount = 0;
@@ -102,7 +101,6 @@
LayoutParams p = (LayoutParams) v.getLayoutParams();
if (p.isOverflowButton) {
- hasOverflow = true;
overflowWidth = v.getMeasuredWidth();
if (hasDividerBeforeChildAt(i)) {
overflowWidth += dividerWidth;
@@ -125,15 +123,12 @@
}
}
- // Try to center non-overflow items with uniformly spaced padding, including on the edges.
- // Overflow will always pin to the right edge. If there isn't enough room for that,
- // center in the remaining space.
+ // Fill action items from the left. Overflow will always pin to the right edge.
if (nonOverflowWidth <= widthRemaining - overflowWidth) {
widthRemaining -= overflowWidth;
}
- final int spacing = (widthRemaining - nonOverflowWidth) / (nonOverflowCount + 1);
- int startLeft = getPaddingLeft() + overflowWidth + spacing;
+ int startLeft = getPaddingLeft();
for (int i = 0; i < childCount; i++) {
final View v = getChildAt(i);
final LayoutParams lp = (LayoutParams) v.getLayoutParams();
@@ -146,7 +141,7 @@
int height = v.getMeasuredHeight();
int t = midVertical - (height / 2);
v.layout(startLeft, t, startLeft + width, t + height);
- startLeft += width + lp.rightMargin + spacing;
+ startLeft += width + lp.rightMargin;
}
}
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
index 4ec131c..99a2d04 100644
--- a/core/jni/android_os_ParcelFileDescriptor.cpp
+++ b/core/jni/android_os_ParcelFileDescriptor.cpp
@@ -34,20 +34,37 @@
jfieldID mFileDescriptor;
} gParcelFileDescriptorOffsets;
-static int android_os_ParcelFileDescriptor_createPipeNative(JNIEnv* env,
+static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromFd(JNIEnv* env,
+ jobject clazz, jint origfd)
+{
+ int fd = dup(origfd);
+ if (fd < 0) {
+ jniThrowException(env, "java/io/IOException", strerror(errno));
+ return NULL;
+ }
+ return jniCreateFileDescriptor(env, fd);
+}
+
+static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromFdNoDup(JNIEnv* env,
+ jobject clazz, jint fd)
+{
+ return jniCreateFileDescriptor(env, fd);
+}
+
+static void android_os_ParcelFileDescriptor_createPipeNative(JNIEnv* env,
jobject clazz, jobjectArray outFds)
{
int fds[2];
if (pipe(fds) < 0) {
- return -errno;
+ int therr = errno;
+ jniThrowException(env, "java/io/IOException", strerror(therr));
+ return;
}
for (int i=0; i<2; i++) {
jobject fdObj = jniCreateFileDescriptor(env, fds[i]);
env->SetObjectArrayElement(outFds, i, fdObj);
}
-
- return 0;
}
static jint getFd(JNIEnv* env, jobject clazz)
@@ -102,7 +119,11 @@
}
static const JNINativeMethod gParcelFileDescriptorMethods[] = {
- {"createPipeNative", "([Ljava/io/FileDescriptor;)I",
+ {"getFileDescriptorFromFd", "(I)Ljava/io/FileDescriptor;",
+ (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromFd},
+ {"getFileDescriptorFromFdNoDup", "(I)Ljava/io/FileDescriptor;",
+ (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromFdNoDup},
+ {"createPipeNative", "([Ljava/io/FileDescriptor;)V",
(void*)android_os_ParcelFileDescriptor_createPipeNative},
{"getStatSize", "()J",
(void*)android_os_ParcelFileDescriptor_getStatSize},
diff --git a/core/res/res/drawable-hdpi/keyboard_textfield_selected.9.png b/core/res/res/drawable-hdpi/keyboard_textfield_selected.9.png
deleted file mode 100644
index 61db22c..0000000
--- a/core/res/res/drawable-hdpi/keyboard_textfield_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/keyboard_textfield_selected.9.png b/core/res/res/drawable-ldpi/keyboard_textfield_selected.9.png
deleted file mode 100644
index d6478fb..0000000
--- a/core/res/res/drawable-ldpi/keyboard_textfield_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/keyboard_textfield_selected.9.png b/core/res/res/drawable-mdpi/keyboard_textfield_selected.9.png
deleted file mode 100644
index 6e703af..0000000
--- a/core/res/res/drawable-mdpi/keyboard_textfield_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/extract_edit_text.xml b/core/res/res/drawable/extract_edit_text.xml
deleted file mode 100644
index c7f66f6..0000000
--- a/core/res/res/drawable/extract_edit_text.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true" android:drawable="@drawable/keyboard_textfield_selected" />
- <item android:drawable="@drawable/textfield_disabled" />
-</selector>
-
diff --git a/core/res/res/layout-large/keyguard.xml b/core/res/res/layout-sw600dp/keyguard.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard.xml
rename to core/res/res/layout-sw600dp/keyguard.xml
diff --git a/core/res/res/layout-large/keyguard_screen_glogin_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_glogin_unlock.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_glogin_unlock.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_glogin_unlock.xml
diff --git a/core/res/res/layout-large/keyguard_screen_lock.xml b/core/res/res/layout-sw600dp/keyguard_screen_lock.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_lock.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_lock.xml
diff --git a/core/res/res/layout-large/keyguard_screen_password_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_password_landscape.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml
diff --git a/core/res/res/layout-large/keyguard_screen_password_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_password_portrait.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml
diff --git a/core/res/res/layout-large/keyguard_screen_sim_pin_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_sim_pin_landscape.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml
diff --git a/core/res/res/layout-large/keyguard_screen_sim_pin_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_portrait.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_sim_pin_portrait.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_sim_pin_portrait.xml
diff --git a/core/res/res/layout-large/keyguard_screen_status_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_status_land.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
diff --git a/core/res/res/layout-large/keyguard_screen_status_port.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_status_port.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
diff --git a/core/res/res/layout-large/keyguard_screen_tab_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_tab_unlock.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
diff --git a/core/res/res/layout-large/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_tab_unlock_land.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
diff --git a/core/res/res/layout-large/keyguard_screen_unlock_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_unlock_landscape.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
diff --git a/core/res/res/layout-large/keyguard_screen_unlock_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
similarity index 100%
rename from core/res/res/layout-large/keyguard_screen_unlock_portrait.xml
rename to core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
diff --git a/core/res/res/layout/input_method_extract_view.xml b/core/res/res/layout/input_method_extract_view.xml
index 689ba7b..7d59d02 100644
--- a/core/res/res/layout/input_method_extract_view.xml
+++ b/core/res/res/layout/input_method_extract_view.xml
@@ -31,7 +31,6 @@
android:gravity="top"
android:minLines="1"
android:inputType="text"
- android:background="@android:drawable/extract_edit_text"
>
</android.inputmethodservice.ExtractEditText>
diff --git a/core/res/res/values-xlarge/config.xml b/core/res/res/values-sw600dp/config.xml
similarity index 99%
rename from core/res/res/values-xlarge/config.xml
rename to core/res/res/values-sw600dp/config.xml
index 4c8bbe6..49ace34 100644
--- a/core/res/res/values-xlarge/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -27,6 +27,7 @@
<!-- Show sliding tab before lockscreen -->
<bool name="config_enableSlidingTabFirst">false</bool>
+
<!-- Enable lockscreen rotation -->
<bool name="config_enableLockScreenRotation">true</bool>
diff --git a/core/res/res/values-xlarge/dimens.xml b/core/res/res/values-xlarge/dimens.xml
index e058442..b906e1a 100644
--- a/core/res/res/values-xlarge/dimens.xml
+++ b/core/res/res/values-xlarge/dimens.xml
@@ -25,10 +25,6 @@
<!-- Size of the giant number (unread count) in the notifications -->
<dimen name="status_bar_content_number_size">48sp</dimen>
- <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
- <!-- Margin for permanent screen decorations at the bottom. -->
- <dimen name="screen_margin_bottom">48dip</dimen>
-
<!-- Default height of a key in the password keyboard for alpha -->
<dimen name="password_keyboard_key_height_alpha">75dip</dimen>
<!-- Default height of a key in the password keyboard for numeric -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6c18089..ebb70e3 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -823,6 +823,10 @@
Default value is false. EditText content is always selectable. -->
<attr name="textIsSelectable" format="boolean" />
+ <!-- When true, IME suggestions will be displayed when the user double taps on editable text.
+ The default value is true. -->
+ <attr name="suggestionsEnabled" format="boolean" />
+
<!-- Where to ellipsize text. -->
<attr name="ellipsize">
<enum name="none" value="0" />
@@ -2877,6 +2881,8 @@
<!-- Indicates that the content of a non-editable text can be selected. -->
<attr name="textIsSelectable" />
+ <!-- Suggestions will be displayed when the user double taps on editable text. -->
+ <attr name="suggestionsEnabled" />
</declare-styleable>
<!-- An <code>input-extras</code> is a container for extra data to supply to
an input method. Contains
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 39d2329..6529fe1 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -77,6 +77,7 @@
<drawable name="dialog_holo_light_frame">@drawable/dialog_full_holo_light</drawable>
<drawable name="input_method_fullscreen_background">#fff9f9f9</drawable>
+ <drawable name="input_method_fullscreen_background_holo">@drawable/screen_background_holo_dark</drawable>
<!-- For date picker widget -->
<drawable name="selected_day_background">#ff0092f4</drawable>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 8ad8f67..1957b2a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1670,5 +1670,6 @@
<public type="attr" name="horizontalDirection" />
<public type="attr" name="fullBackupAgent" />
+ <public type="attr" name="suggestionsEnabled" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 158d524..ccb3518 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2449,6 +2449,20 @@
<!-- See SMS_DIALOG. This is a button choice to disallow sending the SMSes.. -->
<string name="sms_control_no">Cancel</string>
+ <!-- SIM swap and device reboot Dialog --> <skip />
+ <!-- See SIM_REMOVED_DIALOG. This is the title of that dialog. -->
+ <string name="sim_removed_title">SIM card removed</string>
+ <!-- See SIM_REMOVED_DIALOG. This is the message of that dialog. -->
+ <string name="sim_removed_message">The mobile network will be unavailable until you replace the SIM card.</string>
+ <!-- See SIM_REMOVED_DIALOG. This is the button of that dialog. -->
+ <string name="sim_done_button">Done</string>
+ <!-- See SIM_ADDED_DIALOG. This is the title of that dialog. -->
+ <string name="sim_added_title">SIM card added</string>
+ <!-- See SIM_ADDED_DIALOG. This is the message of that dialog. -->
+ <string name="sim_added_message">You must restart your device to access the mobile network.</string>
+ <!-- See SIM_ADDED_DIALOG. This is the button of that dialog. -->
+ <string name="sim_restart_button">Restart</string>
+
<!-- Date/Time picker dialogs strings -->
<!-- The title of the time picker dialog. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index aa9ddff..0a614b2 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -681,7 +681,7 @@
and a few custom attributes. -->
<style name="Theme.Holo.InputMethod" parent="Theme.Holo.Panel">
<item name="android:windowAnimationStyle">@android:style/Animation.InputMethod</item>
- <item name="android:imeFullscreenBackground">@android:drawable/input_method_fullscreen_background</item>
+ <item name="android:imeFullscreenBackground">@android:drawable/input_method_fullscreen_background_holo</item>
<item name="android:imeExtractEnterAnimation">@android:anim/input_method_extract_enter</item>
<item name="android:imeExtractExitAnimation">@android:anim/input_method_extract_exit</item>
</style>
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
new file mode 100644
index 0000000..45719c2
--- /dev/null
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 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.net;
+
+import android.os.SystemClock;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+@SmallTest
+public class NetworkStatsTest extends TestCase {
+
+ private static final String TEST_IFACE = "test0";
+
+ public void testFindIndex() throws Exception {
+ final NetworkStats stats = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 3)
+ .addEntry(TEST_IFACE, 100, 1024, 0)
+ .addEntry(TEST_IFACE, 101, 0, 1024)
+ .addEntry(TEST_IFACE, 102, 1024, 1024).build();
+
+ assertEquals(2, stats.findIndex(TEST_IFACE, 102));
+ assertEquals(2, stats.findIndex(TEST_IFACE, 102));
+ assertEquals(0, stats.findIndex(TEST_IFACE, 100));
+ assertEquals(-1, stats.findIndex(TEST_IFACE, 6));
+ }
+
+ public void testSubtractIdenticalData() throws Exception {
+ final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+ .addEntry(TEST_IFACE, 100, 1024, 0)
+ .addEntry(TEST_IFACE, 101, 0, 1024).build();
+
+ final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+ .addEntry(TEST_IFACE, 100, 1024, 0)
+ .addEntry(TEST_IFACE, 101, 0, 1024).build();
+
+ final NetworkStats result = after.subtract(before);
+
+ assertEquals(0, result.rx[0]);
+ assertEquals(0, result.tx[0]);
+ assertEquals(0, result.rx[1]);
+ assertEquals(0, result.tx[1]);
+ }
+
+ public void testSubtractIdenticalRows() throws Exception {
+ final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+ .addEntry(TEST_IFACE, 100, 1024, 0)
+ .addEntry(TEST_IFACE, 101, 0, 1024).build();
+
+ final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+ .addEntry(TEST_IFACE, 100, 1025, 2)
+ .addEntry(TEST_IFACE, 101, 3, 1028).build();
+
+ final NetworkStats result = after.subtract(before);
+
+ // expect delta between measurements
+ assertEquals(1, result.rx[0]);
+ assertEquals(2, result.tx[0]);
+ assertEquals(3, result.rx[1]);
+ assertEquals(4, result.tx[1]);
+ }
+
+ public void testSubtractNewRows() throws Exception {
+ final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+ .addEntry(TEST_IFACE, 100, 1024, 0)
+ .addEntry(TEST_IFACE, 101, 0, 1024).build();
+
+ final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 3)
+ .addEntry(TEST_IFACE, 100, 1024, 0)
+ .addEntry(TEST_IFACE, 101, 0, 1024)
+ .addEntry(TEST_IFACE, 102, 1024, 1024).build();
+
+ final NetworkStats result = after.subtract(before);
+
+ // its okay to have new rows
+ assertEquals(0, result.rx[0]);
+ assertEquals(0, result.tx[0]);
+ assertEquals(0, result.rx[1]);
+ assertEquals(0, result.tx[1]);
+ assertEquals(1024, result.rx[2]);
+ assertEquals(1024, result.tx[2]);
+ }
+
+}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index fb7a871..70053ea 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -400,6 +400,7 @@
}
void AwesomePlayer::reset() {
+ LOGI("reset");
Mutex::Autolock autoLock(mLock);
reset_l();
}
@@ -413,8 +414,10 @@
Playback::STOP, 0);
mDecryptHandle = NULL;
mDrmManagerClient = NULL;
+ LOGI("DRM manager client stopped");
}
+
if (mFlags & PLAYING) {
uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
@@ -447,6 +450,7 @@
mPreparedCondition.wait(mLock);
}
+ LOGI("cancel player events");
cancelPlayerEvents();
mWVMExtractor.clear();
@@ -1081,6 +1085,7 @@
usleep(1000);
}
IPCThreadState::self()->flushCommands();
+ LOGI("video decoder shutdown completed");
}
void AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 0f0ffd4..ba495cc 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -3443,7 +3443,7 @@
}
status_t OMXCodec::stop() {
- CODEC_LOGV("stop mState=%d", mState);
+ CODEC_LOGI("stop mState=%d", mState);
Mutex::Autolock autoLock(mLock);
@@ -3505,6 +3505,7 @@
mLeftOverBuffer = NULL;
}
+ CODEC_LOGI("stopping video source");
mSource->stop();
CODEC_LOGI("stopped in state %d", mState);
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index afefee6..ff45edc 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -14,7 +14,6 @@
EGL/eglApi.cpp \
EGL/trace.cpp \
EGL/getProcAddress.cpp.arm \
- EGL/hooks.cpp \
EGL/Loader.cpp \
#
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index da26229..e94e50e 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -26,11 +26,10 @@
#include <EGL/egl.h>
-#include "hooks.h"
-#include "egl_impl.h"
-
-#include "Loader.h"
+#include "egldefs.h"
#include "glesv2dbg.h"
+#include "hooks.h"
+#include "Loader.h"
// ----------------------------------------------------------------------------
namespace android {
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 31fe306..b11db32 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -33,6 +33,7 @@
#include <utils/String8.h>
+#include "egldefs.h"
#include "egl_impl.h"
#include "egl_tls.h"
#include "glesv2dbg.h"
@@ -278,6 +279,71 @@
return res;
}
+void gl_unimplemented() {
+ LOGE("called unimplemented OpenGL ES API");
+}
+
+// ----------------------------------------------------------------------------
+
+#if USE_FAST_TLS_KEY
+
+// We have a dedicated TLS slot in bionic
+static inline gl_hooks_t const * volatile * get_tls_hooks() {
+ volatile void *tls_base = __get_tls();
+ gl_hooks_t const * volatile * tls_hooks =
+ reinterpret_cast<gl_hooks_t const * volatile *>(tls_base);
+ return tls_hooks;
+}
+
+void setGlThreadSpecific(gl_hooks_t const *value) {
+ gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
+ tls_hooks[TLS_SLOT_OPENGL_API] = value;
+}
+
+gl_hooks_t const* getGlThreadSpecific() {
+ gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
+ gl_hooks_t const* hooks = tls_hooks[TLS_SLOT_OPENGL_API];
+ if (hooks) return hooks;
+ return &gHooksNoContext;
+}
+
+#else
+
+void setGlThreadSpecific(gl_hooks_t const *value) {
+ pthread_setspecific(gGLWrapperKey, value);
+}
+
+gl_hooks_t const* getGlThreadSpecific() {
+ gl_hooks_t const* hooks = static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
+ if (hooks) return hooks;
+ return &gHooksNoContext;
+}
+
+#endif
+
+// ----------------------------------------------------------------------------
+// GL / EGL hooks
+// ----------------------------------------------------------------------------
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+#define GL_ENTRY(_r, _api, ...) #_api,
+#define EGL_ENTRY(_r, _api, ...) #_api,
+
+char const * const gl_names[] = {
+ #include "entries.in"
+ NULL
+};
+
+char const * const egl_names[] = {
+ #include "egl_entries.in"
+ NULL
+};
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+
+
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 8c482c3..113595f 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -30,6 +30,7 @@
#include <utils/SortedVector.h>
#include <utils/threads.h>
+#include "egldefs.h"
#include "hooks.h"
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_tls.h b/opengl/libs/EGL/egl_tls.h
index 8b31468..a7989ef 100644
--- a/opengl/libs/EGL/egl_tls.h
+++ b/opengl/libs/EGL/egl_tls.h
@@ -21,7 +21,12 @@
#include <EGL/egl.h>
+#include "egldefs.h"
+#include "hooks.h"
+
+// ----------------------------------------------------------------------------
namespace android {
+// ----------------------------------------------------------------------------
class DbgContext;
@@ -58,6 +63,16 @@
#define setError(_e, _r) egl_tls_t::setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
+// ----------------------------------------------------------------------------
+
+#if EGL_TRACE
+
+extern gl_hooks_t const* getGLTraceThreadSpecific();
+
+#endif
+
+// ----------------------------------------------------------------------------
}; // namespace android
+// ----------------------------------------------------------------------------
#endif // ANDROID_EGL_TLS_H
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
new file mode 100644
index 0000000..107acd9
--- /dev/null
+++ b/opengl/libs/EGL/egldefs.h
@@ -0,0 +1,71 @@
+/*
+ ** Copyright 2011, 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.
+ */
+
+#ifndef ANDROID_EGLDEFS_H
+#define ANDROID_EGLDEFS_H
+
+#include "hooks.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 4
+
+// EGLDisplay are global, not attached to a given thread
+const unsigned int NUM_DISPLAYS = 1;
+
+enum {
+ IMPL_HARDWARE = 0,
+ IMPL_SOFTWARE,
+ IMPL_NUM_IMPLEMENTATIONS
+};
+
+enum {
+ GLESv1_INDEX = 0,
+ GLESv2_INDEX = 1,
+};
+
+// ----------------------------------------------------------------------------
+
+struct egl_connection_t
+{
+ inline egl_connection_t() : dso(0) { }
+ void * dso;
+ gl_hooks_t * hooks[2];
+ EGLint major;
+ EGLint minor;
+ egl_t egl;
+};
+
+// ----------------------------------------------------------------------------
+
+extern gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+extern gl_hooks_t gHooksNoContext;
+extern pthread_key_t gGLWrapperKey;
+extern "C" void gl_unimplemented();
+
+extern char const * const gl_names[];
+extern char const * const egl_names[];
+
+extern egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_EGLDEFS_H */
diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
index dcf8735c..f89c865 100644
--- a/opengl/libs/EGL/getProcAddress.cpp
+++ b/opengl/libs/EGL/getProcAddress.cpp
@@ -20,6 +20,7 @@
#include <cutils/log.h>
+#include "egldefs.h"
#include "hooks.h"
// ----------------------------------------------------------------------------
@@ -34,7 +35,7 @@
#undef GL_EXTENSION_LIST
#undef GET_TLS
-#if defined(__arm__)
+#if USE_FAST_TLS_KEY
#ifdef HAVE_ARM_TLS_REGISTER
#define GET_TLS(reg) \
@@ -77,7 +78,7 @@
#define GL_EXTENSION(_n)
- #warning "eglGetProcAddress() partially supported on this architecture"
+ #warning "eglGetProcAddress() partially supported"
#endif
diff --git a/opengl/libs/EGL/hooks.cpp b/opengl/libs/EGL/hooks.cpp
deleted file mode 100644
index 72ad6b3..0000000
--- a/opengl/libs/EGL/hooks.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- ** Copyright 2009, 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.
- */
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <cutils/log.h>
-
-#include "hooks.h"
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-void gl_unimplemented() {
- LOGE("called unimplemented OpenGL ES API");
-}
-
-
-// ----------------------------------------------------------------------------
-// GL / EGL hooks
-// ----------------------------------------------------------------------------
-
-#undef GL_ENTRY
-#undef EGL_ENTRY
-#define GL_ENTRY(_r, _api, ...) #_api,
-#define EGL_ENTRY(_r, _api, ...) #_api,
-
-char const * const gl_names[] = {
- #include "entries.in"
- NULL
-};
-
-char const * const egl_names[] = {
- #include "egl_entries.in"
- NULL
-};
-
-#undef GL_ENTRY
-#undef EGL_ENTRY
-
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
diff --git a/opengl/libs/EGL/trace.cpp b/opengl/libs/EGL/trace.cpp
index f3e101b..0e934e2 100644
--- a/opengl/libs/EGL/trace.cpp
+++ b/opengl/libs/EGL/trace.cpp
@@ -26,6 +26,7 @@
#include <cutils/log.h>
+#include "egl_tls.h"
#include "hooks.h"
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index d24b047..a809316 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -25,27 +25,12 @@
#include "hooks.h"
-#define VERSION_MAJOR 1
-#define VERSION_MINOR 4
-
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
-struct egl_connection_t
-{
- inline egl_connection_t() : dso(0) { }
- void * dso;
- gl_hooks_t * hooks[2];
- EGLint major;
- EGLint minor;
- egl_t egl;
-};
-
EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
-extern egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
-
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index 812e26d..7ac88cd 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -54,22 +54,6 @@
namespace android {
// ----------------------------------------------------------------------------
-// EGLDisplay are global, not attached to a given thread
-const unsigned int NUM_DISPLAYS = 1;
-
-enum {
- IMPL_HARDWARE = 0,
- IMPL_SOFTWARE,
- IMPL_NUM_IMPLEMENTATIONS
-};
-
-enum {
- GLESv1_INDEX = 0,
- GLESv2_INDEX = 1,
-};
-
-// ----------------------------------------------------------------------------
-
// GL / EGL hooks
#undef GL_ENTRY
@@ -92,60 +76,8 @@
#undef GL_ENTRY
#undef EGL_ENTRY
-
-// ----------------------------------------------------------------------------
-
-extern gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
-extern gl_hooks_t gHooksNoContext;
-extern pthread_key_t gGLWrapperKey;
-extern "C" void gl_unimplemented();
-
-extern char const * const gl_names[];
-extern char const * const egl_names[];
-
-// ----------------------------------------------------------------------------
-
-#if USE_FAST_TLS_KEY
-
-// We have a dedicated TLS slot in bionic
-static inline gl_hooks_t const * volatile * get_tls_hooks() {
- volatile void *tls_base = __get_tls();
- gl_hooks_t const * volatile * tls_hooks =
- reinterpret_cast<gl_hooks_t const * volatile *>(tls_base);
- return tls_hooks;
-}
-
-static inline void setGlThreadSpecific(gl_hooks_t const *value) {
- gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
- tls_hooks[TLS_SLOT_OPENGL_API] = value;
-}
-
-static gl_hooks_t const* getGlThreadSpecific() {
- gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
- gl_hooks_t const* hooks = tls_hooks[TLS_SLOT_OPENGL_API];
- if (hooks) return hooks;
- return &gHooksNoContext;
-}
-
-#else
-
-static inline void setGlThreadSpecific(gl_hooks_t const *value) {
- pthread_setspecific(gGLWrapperKey, value);
-}
-
-static gl_hooks_t const* getGlThreadSpecific() {
- gl_hooks_t const* hooks = static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
- if (hooks) return hooks;
- return &gHooksNoContext;
-}
-
-#endif
-
-#if EGL_TRACE
-
-extern gl_hooks_t const* getGLTraceThreadSpecific();
-
-#endif
+EGLAPI void setGlThreadSpecific(gl_hooks_t const *value);
+EGLAPI gl_hooks_t const* getGlThreadSpecific();
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/packages/SystemUI/res/layout-large/status_bar.xml b/packages/SystemUI/res/layout-sw600dp/status_bar.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_input_methods_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_input_methods_item.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_input_methods_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_panel.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_input_methods_panel.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_panel.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_notification_area.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_notification_area.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_notification_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_notification_panel.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_notification_panel_title.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_notification_panel_title.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_notification_peek.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_peek.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_notification_peek.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_notification_peek.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_notification_row.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_notification_row.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_pocket_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_pocket_panel.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_pocket_panel.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_pocket_panel.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_recent_item.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_recent_panel.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_recent_panel_footer.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel_footer.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_recent_panel_footer.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel_footer.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_settings_view.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_settings_view.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_settings_view.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_settings_view.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_ticker_compat.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_compat.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_ticker_compat.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_ticker_compat.xml
diff --git a/packages/SystemUI/res/layout-large/status_bar_ticker_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
similarity index 100%
rename from packages/SystemUI/res/layout-large/status_bar_ticker_panel.xml
rename to packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
diff --git a/packages/SystemUI/res/values-large/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
similarity index 100%
rename from packages/SystemUI/res/values-large/styles.xml
rename to packages/SystemUI/res/values-sw600dp/styles.xml
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 7c613c1..8f179f5 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -16,51 +16,34 @@
package com.android.server;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
import android.content.pm.PackageManager;
-import android.net.NetworkStats;
-import android.net.Uri;
-import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
+import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
+import android.net.NetworkStats;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.os.Binder;
import android.os.INetworkManagementService;
-import android.os.Handler;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
-import java.util.ArrayList;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
-import android.provider.Settings;
-import android.content.ContentResolver;
-import android.database.ContentObserver;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileReader;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.RandomAccessFile;
-import java.io.Reader;
-import java.lang.IllegalStateException;
-import java.net.InetAddress;
import java.net.Inet4Address;
-import java.net.UnknownHostException;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;
import libcore.io.IoUtils;
@@ -69,14 +52,16 @@
* @hide
*/
class NetworkManagementService extends INetworkManagementService.Stub {
-
- private static final String TAG = "NetworkManagmentService";
+ private static final String TAG = "NetworkManagementService";
private static final boolean DBG = false;
private static final String NETD_TAG = "NetdConnector";
private static final int ADD = 1;
private static final int REMOVE = 2;
+ /** Base path to UID-granularity network statistics. */
+ private static final File PATH_PROC_UID_STAT = new File("/proc/uid_stat");
+
class NetdResponseCode {
public static final int InterfaceListResult = 110;
public static final int TetherInterfaceListResult = 111;
@@ -891,7 +876,7 @@
return -1;
}
- /** {@inheritDoc} */
+ @Override
public NetworkStats getNetworkStatsSummary() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
@@ -909,31 +894,46 @@
return stats.build();
}
- /** {@inheritDoc} */
+ @Override
public NetworkStats getNetworkStatsDetail() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- final File procPath = new File("/proc/uid_stat");
- final String[] knownUids = procPath.list();
+ final String[] knownUids = PATH_PROC_UID_STAT.list();
final NetworkStats.Builder stats = new NetworkStats.Builder(
SystemClock.elapsedRealtime(), knownUids.length);
- // TODO: kernel module will provide interface-level stats in future
- // TODO: migrate these stats to come across netd in bulk, instead of all
- // these individual file reads.
for (String uid : knownUids) {
- final File uidPath = new File(procPath, uid);
- final int rx = readSingleIntFromFile(new File(uidPath, "tcp_rcv"));
- final int tx = readSingleIntFromFile(new File(uidPath, "tcp_snd"));
-
final int uidInt = Integer.parseInt(uid);
- stats.addEntry(NetworkStats.IFACE_ALL, uidInt, rx, tx);
+ collectNetworkStatsDetail(stats, uidInt);
}
return stats.build();
}
+ @Override
+ public NetworkStats getNetworkStatsUidDetail(int uid) {
+ if (Binder.getCallingUid() != uid) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+ }
+
+ final NetworkStats.Builder stats = new NetworkStats.Builder(
+ SystemClock.elapsedRealtime(), 1);
+ collectNetworkStatsDetail(stats, uid);
+ return stats.build();
+ }
+
+ private void collectNetworkStatsDetail(NetworkStats.Builder stats, int uid) {
+ // TODO: kernel module will provide interface-level stats in future
+ // TODO: migrate these stats to come across netd in bulk, instead of all
+ // these individual file reads.
+ final File uidPath = new File(PATH_PROC_UID_STAT, Integer.toString(uid));
+ final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
+ final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
+ stats.addEntry(NetworkStats.IFACE_ALL, uid, rx, tx);
+ }
+
public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
@@ -994,22 +994,17 @@
}
/**
- * Utility method to read a single plain-text {@link Integer} from the given
+ * Utility method to read a single plain-text {@link Long} from the given
* {@link File}, usually from a {@code /proc/} filesystem.
*/
- private static int readSingleIntFromFile(File file) {
- RandomAccessFile f = null;
+ private static long readSingleLongFromFile(File file) {
try {
- f = new RandomAccessFile(file, "r");
- byte[] buffer = new byte[(int) f.length()];
- f.readFully(buffer);
- return Integer.parseInt(new String(buffer).trim());
+ final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
+ return Long.parseLong(new String(buffer).trim());
} catch (NumberFormatException e) {
return -1;
} catch (IOException e) {
return -1;
- } finally {
- IoUtils.closeQuietly(f);
}
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cd8915d..5355d44 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -18,6 +18,7 @@
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.am.ActivityManagerService;
+import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.pm.PackageManagerService;
import com.android.server.usb.UsbService;
import com.android.server.wm.WindowManagerService;
@@ -119,6 +120,7 @@
LightsService lights = null;
PowerManagerService power = null;
BatteryService battery = null;
+ NetworkPolicyManagerService networkPolicy = null;
ConnectivityService connectivity = null;
IPackageManager pm = null;
Context context = null;
@@ -282,6 +284,15 @@
}
try {
+ Slog.i(TAG, "NetworkPolicy Service");
+ networkPolicy = new NetworkPolicyManagerService(
+ context, ActivityManagerService.self(), power);
+ ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting Connectivity Service", e);
+ }
+
+ try {
Slog.i(TAG, "NetworkManagement Service");
ServiceManager.addService(
Context.NETWORKMANAGEMENT_SERVICE,
@@ -528,6 +539,7 @@
// These are needed to propagate to the runnable below.
final Context contextF = context;
final BatteryService batteryF = battery;
+ final NetworkPolicyManagerService networkPolicyF = networkPolicy;
final ConnectivityService connectivityF = connectivity;
final DockObserver dockF = dock;
final UsbService usbF = usb;
@@ -553,6 +565,7 @@
startSystemUi(contextF);
if (batteryF != null) batteryF.systemReady();
+ if (networkPolicyF != null) networkPolicyF.systemReady();
if (connectivityF != null) connectivityF.systemReady();
if (dockF != null) dockF.systemReady();
if (usbF != null) usbF.systemReady();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 5aae539..568183b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -43,6 +43,7 @@
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
import android.app.INotificationManager;
+import android.app.IProcessObserver;
import android.app.IServiceConnection;
import android.app.IThumbnailReceiver;
import android.app.IThumbnailRetriever;
@@ -752,8 +753,6 @@
*/
final UsageStatsService mUsageStatsService;
- final NetworkPolicyManagerService mNetworkPolicyService;
-
/**
* Current configuration information. HistoryRecord objects are given
* a reference to this object to indicate which configuration they are
@@ -885,7 +884,10 @@
final RemoteCallbackList<IActivityWatcher> mWatchers
= new RemoteCallbackList<IActivityWatcher>();
-
+
+ final RemoteCallbackList<IProcessObserver> mProcessObservers
+ = new RemoteCallbackList<IProcessObserver>();
+
/**
* Callback of last caller to {@link #requestPss}.
*/
@@ -1277,16 +1279,15 @@
}
} break;
case DISPATCH_FOREGROUND_ACTIVITIES_CHANGED: {
- // Flag might have changed during dispatch, but it's always
- // consistent since we dispatch for every change.
final ProcessRecord app = (ProcessRecord) msg.obj;
- mNetworkPolicyService.onForegroundActivitiesChanged(
- app.info.uid, app.pid, app.foregroundActivities);
+ final boolean foregroundActivities = msg.arg1 != 0;
+ dispatchForegroundActivitiesChanged(
+ app.pid, app.info.uid, foregroundActivities);
break;
}
case DISPATCH_PROCESS_DIED: {
final ProcessRecord app = (ProcessRecord) msg.obj;
- mNetworkPolicyService.onProcessDied(app.info.uid, app.pid);
+ dispatchProcessDied(app.pid, app.info.uid);
break;
}
}
@@ -1358,7 +1359,6 @@
m.mBatteryStatsService.publish(context);
m.mUsageStatsService.publish(context);
- m.mNetworkPolicyService.publish(context);
synchronized (thr) {
thr.mReady = true;
@@ -1480,8 +1480,6 @@
mUsageStatsService = new UsageStatsService(new File(
systemDir, "usagestats").toString());
- mNetworkPolicyService = new NetworkPolicyManagerService();
-
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -2152,6 +2150,36 @@
mWatchers.finishBroadcast();
}
+ private void dispatchForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
+ int i = mProcessObservers.beginBroadcast();
+ while (i > 0) {
+ i--;
+ final IProcessObserver observer = mProcessObservers.getBroadcastItem(i);
+ if (observer != null) {
+ try {
+ observer.onForegroundActivitiesChanged(pid, uid, foregroundActivities);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ mProcessObservers.finishBroadcast();
+ }
+
+ private void dispatchProcessDied(int pid, int uid) {
+ int i = mProcessObservers.beginBroadcast();
+ while (i > 0) {
+ i--;
+ final IProcessObserver observer = mProcessObservers.getBroadcastItem(i);
+ if (observer != null) {
+ try {
+ observer.onProcessDied(pid, uid);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ mProcessObservers.finishBroadcast();
+ }
+
final void doPendingActivityLaunchesLocked(boolean doResume) {
final int N = mPendingActivityLaunches.size();
if (N <= 0) {
@@ -6084,7 +6112,6 @@
mUsageStatsService.shutdown();
mBatteryStatsService.shutdown();
- mNetworkPolicyService.shutdown();
return timedout;
}
@@ -6241,6 +6268,14 @@
}
}
+ public void registerProcessObserver(IProcessObserver observer) {
+ mProcessObservers.register(observer);
+ }
+
+ public void unregisterProcessObserver(IProcessObserver observer) {
+ mProcessObservers.unregister(observer);
+ }
+
public void setImmersive(IBinder token, boolean immersive) {
synchronized(this) {
int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
@@ -12755,7 +12790,8 @@
app.curSchedGroup = schedGroup;
if (hadForegroundActivities != app.foregroundActivities) {
- mHandler.obtainMessage(DISPATCH_FOREGROUND_ACTIVITIES_CHANGED, app).sendToTarget();
+ mHandler.obtainMessage(DISPATCH_FOREGROUND_ACTIVITIES_CHANGED,
+ app.foregroundActivities ? 1 : 0, 0, app).sendToTarget();
}
return adj;
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index a7a4f07..d083d01 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -19,13 +19,20 @@
import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.net.NetworkPolicyManager.POLICY_NONE;
-import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID;
import static android.net.NetworkPolicyManager.POLICY_REJECT_BACKGROUND;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID;
+import android.app.IActivityManager;
+import android.app.IProcessObserver;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.INetworkPolicyManager;
-import android.os.ServiceManager;
+import android.os.IPowerManager;
+import android.os.RemoteException;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
@@ -38,92 +45,139 @@
private static final String TAG = "NetworkPolicy";
private static final boolean LOGD = true;
- private static final String SERVICE_NAME = "netpolicy";
-
private Context mContext;
+ private IActivityManager mActivityManager;
+ private IPowerManager mPowerManager;
+
+ private Object mRulesLock = new Object();
+
+ private boolean mScreenOn = false;
/** Current network policy for each UID. */
- private SparseIntArray mUidPolicy;
+ private SparseIntArray mUidPolicy = new SparseIntArray();
/** Foreground at both UID and PID granularity. */
- private SparseBooleanArray mUidForeground;
- private SparseArray<SparseBooleanArray> mUidPidForeground;
+ private SparseBooleanArray mUidForeground = new SparseBooleanArray();
+ private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
+ SparseBooleanArray>();
// TODO: periodically poll network stats and write to disk
// TODO: save/restore policy information from disk
- // TODO: watch screen on/off broadcasts to track foreground
+ public NetworkPolicyManagerService(
+ Context context, IActivityManager activityManager, IPowerManager powerManager) {
+ mContext = checkNotNull(context, "missing context");
+ mActivityManager = checkNotNull(activityManager, "missing activityManager");
+ mPowerManager = checkNotNull(powerManager, "missing powerManager");
+ }
- public void publish(Context context) {
- mContext = context;
- ServiceManager.addService(SERVICE_NAME, asBinder());
-
- mUidPolicy = new SparseIntArray();
- mUidForeground = new SparseBooleanArray();
- mUidPidForeground = new SparseArray<SparseBooleanArray>();
-
- // TODO: register for NetworkManagementService callbacks
+ public void systemReady() {
// TODO: read current policy+stats from disk and generate NMS rules
- }
- public void shutdown() {
- // TODO: persist any pending stats during clean shutdown
+ updateScreenOn();
- mUidPolicy = null;
- mUidForeground = null;
- mUidPidForeground = null;
- }
-
- @Override
- public void onForegroundActivitiesChanged(int uid, int pid, boolean foreground) {
- // only someone like AMS should only be calling us
- mContext.enforceCallingOrSelfPermission(
- MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission");
-
- // because a uid can have multiple pids running inside, we need to
- // remember all pid states and summarize foreground at uid level.
-
- // record foreground for this specific pid
- SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
- if (pidForeground == null) {
- pidForeground = new SparseBooleanArray(2);
- mUidPidForeground.put(uid, pidForeground);
+ try {
+ mActivityManager.registerProcessObserver(mProcessObserver);
+ } catch (RemoteException e) {
+ // ouch, no foregroundActivities updates means some processes may
+ // never get network access.
+ Slog.e(TAG, "unable to register IProcessObserver", e);
}
- pidForeground.put(pid, foreground);
- computeUidForeground(uid);
+
+ // TODO: traverse existing processes to know foreground state, or have
+ // activitymanager dispatch current state when new observer attached.
+
+ final IntentFilter screenFilter = new IntentFilter();
+ screenFilter.addAction(Intent.ACTION_SCREEN_ON);
+ screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
+ mContext.registerReceiver(mScreenReceiver, screenFilter);
+
+ final IntentFilter shutdownFilter = new IntentFilter();
+ shutdownFilter.addAction(Intent.ACTION_SHUTDOWN);
+ mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
+
}
- @Override
- public void onProcessDied(int uid, int pid) {
- // only someone like AMS should only be calling us
- mContext.enforceCallingOrSelfPermission(
- MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission");
+ private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
+ @Override
+ public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
+ // only someone like AMS should only be calling us
+ mContext.enforceCallingOrSelfPermission(
+ MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission");
- // clear records and recompute, when they exist
- final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
- if (pidForeground != null) {
- pidForeground.delete(pid);
- computeUidForeground(uid);
+ synchronized (mRulesLock) {
+ // because a uid can have multiple pids running inside, we need to
+ // remember all pid states and summarize foreground at uid level.
+
+ // record foreground for this specific pid
+ SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
+ if (pidForeground == null) {
+ pidForeground = new SparseBooleanArray(2);
+ mUidPidForeground.put(uid, pidForeground);
+ }
+ pidForeground.put(pid, foregroundActivities);
+ computeUidForegroundL(uid);
+ }
}
- }
+
+ @Override
+ public void onProcessDied(int pid, int uid) {
+ // only someone like AMS should only be calling us
+ mContext.enforceCallingOrSelfPermission(
+ MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission");
+
+ synchronized (mRulesLock) {
+ // clear records and recompute, when they exist
+ final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
+ if (pidForeground != null) {
+ pidForeground.delete(pid);
+ computeUidForegroundL(uid);
+ }
+ }
+ }
+ };
+
+ private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (mRulesLock) {
+ // screen-related broadcasts are protected by system, no need
+ // for permissions check.
+ updateScreenOn();
+ }
+ }
+ };
+
+ private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // TODO: persist any pending stats during clean shutdown
+ Log.d(TAG, "persisting stats");
+ }
+ };
@Override
public void setUidPolicy(int uid, int policy) {
mContext.enforceCallingOrSelfPermission(
UPDATE_DEVICE_STATS, "requires UPDATE_DEVICE_STATS permission");
- mUidPolicy.put(uid, policy);
+
+ synchronized (mRulesLock) {
+ mUidPolicy.put(uid, policy);
+ }
}
@Override
public int getUidPolicy(int uid) {
- return mUidPolicy.get(uid, POLICY_NONE);
+ synchronized (mRulesLock) {
+ return mUidPolicy.get(uid, POLICY_NONE);
+ }
}
/**
* Foreground for PID changed; recompute foreground at UID level. If
- * changed, will trigger {@link #updateRulesForUid(int)}.
+ * changed, will trigger {@link #updateRulesForUidL(int)}.
*/
- private void computeUidForeground(int uid) {
+ private void computeUidForegroundL(int uid) {
final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
// current pid is dropping foreground; examine other pids
@@ -140,12 +194,37 @@
if (oldUidForeground != uidForeground) {
// foreground changed, push updated rules
mUidForeground.put(uid, uidForeground);
- updateRulesForUid(uid);
+ updateRulesForUidL(uid);
}
}
- private void updateRulesForUid(int uid) {
- final boolean uidForeground = mUidForeground.get(uid, false);
+ private void updateScreenOn() {
+ synchronized (mRulesLock) {
+ try {
+ mScreenOn = mPowerManager.isScreenOn();
+ } catch (RemoteException e) {
+ }
+ updateRulesForScreenL();
+ }
+ }
+
+ /**
+ * Update rules that might be changed by {@link #mScreenOn} value.
+ */
+ private void updateRulesForScreenL() {
+ // only update rules for anyone with foreground activities
+ final int size = mUidForeground.size();
+ for (int i = 0; i < size; i++) {
+ if (mUidForeground.valueAt(i)) {
+ final int uid = mUidForeground.keyAt(i);
+ updateRulesForUidL(uid);
+ }
+ }
+ }
+
+ private void updateRulesForUidL(int uid) {
+ // only really in foreground when screen on
+ final boolean uidForeground = mUidForeground.get(uid, false) && mScreenOn;
final int uidPolicy = getUidPolicy(uid);
if (LOGD) {
@@ -162,4 +241,10 @@
}
}
+ private static <T> T checkNotNull(T value, String message) {
+ if (value == null) {
+ throw new NullPointerException(message);
+ }
+ return value;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
index f20d5e5..ca33d32 100644
--- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
@@ -42,6 +42,7 @@
import android.os.SystemClock;
import android.provider.Settings;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
import android.text.format.DateUtils;
import android.util.Log;
@@ -54,6 +55,7 @@
/**
* Tests for {@link ThrottleService}.
*/
+@LargeTest
public class ThrottleServiceTest extends AndroidTestCase {
private static final String TAG = "ThrottleServiceTest";
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index 9fc4667..0c4581b 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -25,6 +25,11 @@
import android.os.SystemProperties;
import android.util.Log;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* {@hide}
*/
@@ -794,6 +799,34 @@
}
/**
+ * The contents of the /proc/cmdline file
+ */
+ private static String getProcCmdLine()
+ {
+ String cmdline = "";
+ FileInputStream is = null;
+ try {
+ is = new FileInputStream("/proc/cmdline");
+ byte [] buffer = new byte[2048];
+ int count = is.read(buffer);
+ if (count > 0) {
+ cmdline = new String(buffer, 0, count);
+ }
+ } catch (IOException e) {
+ Log.d(LOG_TAG, "No /proc/cmdline exception=" + e);
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ Log.d(LOG_TAG, "/proc/cmdline=" + cmdline);
+ return cmdline;
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -801,6 +834,17 @@
return getLteOnCdmaModeStatic();
}
+ /** Kernel command line */
+ private static final String sKernelCmdLine = getProcCmdLine();
+
+ /** Pattern for selecting the product type from the kernel command line */
+ private static final Pattern sProductTypePattern =
+ Pattern.compile("\\sproduct_type\\s*=\\s*(\\w+)");
+
+ /** The ProductType used for LTE on CDMA devices */
+ private static final String sLteOnCdmaProductType =
+ SystemProperties.get(TelephonyProperties.PROPERTY_LTE_ON_CDMA_PRODUCT_TYPE, "");
+
/**
* Return if the current radio is LTE on CDMA. This
* is a tri-state return value as for a period of time
@@ -810,9 +854,24 @@
* or {@link Phone#LTE_ON_CDMA_TRUE}
*/
public static int getLteOnCdmaModeStatic() {
- int retVal = SystemProperties.getInt(TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA,
- Phone.LTE_ON_CDMA_FALSE);
- Log.d(LOG_TAG, "getLteOnCdmaMode=" + retVal);
+ int retVal;
+ String productType;
+
+ Matcher matcher = sProductTypePattern.matcher(sKernelCmdLine);
+ if (matcher.find()) {
+ productType = matcher.group(1);
+ if (sLteOnCdmaProductType.equals(productType)) {
+ retVal = Phone.LTE_ON_CDMA_TRUE;
+ } else {
+ retVal = Phone.LTE_ON_CDMA_FALSE;
+ }
+ } else {
+ retVal = Phone.LTE_ON_CDMA_FALSE;
+ productType = "";
+ }
+
+ Log.d(LOG_TAG, "getLteOnCdmaMode=" + retVal + " product_type='" + productType +
+ "' lteOnCdmaProductType='" + sLteOnCdmaProductType + "'");
return retVal;
}
}
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 2e781b2..3636baa 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -22,8 +22,10 @@
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import android.net.LinkAddress;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
+import android.net.NetworkUtils;
import android.net.ProxyProperties;
import android.os.AsyncResult;
import android.os.Bundle;
@@ -33,6 +35,7 @@
import android.os.SystemProperties;
import android.text.TextUtils;
+import java.util.Collection;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
@@ -202,6 +205,7 @@
protected long lastFailTime;
protected FailCause lastFailCause;
protected static final String NULL_IP = "0.0.0.0";
+ private int mRefCount;
Object userData;
//***** Abstract methods
@@ -249,6 +253,8 @@
Message m = dp.onCompletedMsg;
if (TextUtils.equals(dp.reason, Phone.REASON_RADIO_TURNED_OFF)) {
discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
+ } else if (TextUtils.equals(dp.reason, Phone.REASON_PDP_RESET)) {
+ discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET;
}
}
if (phone.mCM.getRadioState().isOn()) {
@@ -408,49 +414,6 @@
return mRetryMgr.configure(configStr);
}
- private AtomicInteger mRefCount = new AtomicInteger(0);
-
- /**
- * Set refCount.
- *
- * @param val is new refCount
- */
- public void setRefCount(int val) {
- mRefCount.set(val);
- }
-
- /**
- * Get refCount
- *
- * @return refCount
- */
- public int getRefCount() {
- return mRefCount.get();
- }
-
- /**
- * @return decrement and return refCount
- *
- * TODO: Consider using the refCount for defining the
- * life time of a connection. When this goes zero the
- * DataConnection could tear itself down.
- */
- public int decAndGetRefCount() {
- int v = mRefCount.decrementAndGet();
- if (v < 0) {
- log("BUG: decAndGetRefCount caused refCount to be < 0");
- mRefCount.set(0);
- }
- return v;
- }
-
- /**
- * @return increment and return refCount
- */
- public int incAndGetRefCount() {
- return mRefCount.incrementAndGet();
- }
-
/*
* **************************************************************************
* End members owned by DataConnectionTracker
@@ -466,6 +429,7 @@
createTime = -1;
lastFailTime = -1;
lastFailCause = FailCause.NONE;
+ mRefCount = 0;
mLinkProperties = new LinkProperties();
mApn = null;
@@ -531,8 +495,10 @@
return response.setLinkProperties(lp, okToUseSystemPropertyDns);
}
- private boolean updateLinkProperty(DataCallState newState) {
- boolean changed = false;
+ private DataConnectionAc.LinkPropertyChangeAction updateLinkProperty(
+ DataCallState newState) {
+ DataConnectionAc.LinkPropertyChangeAction changed =
+ DataConnectionAc.LinkPropertyChangeAction.NONE;
if (newState == null) return changed;
@@ -551,9 +517,23 @@
if (DBG) log("old LP=" + mLinkProperties);
if (DBG) log("new LP=" + newLp);
+ // Check consistency of link address. Currently we expect
+ // only one "global" address is assigned per each IP type.
+ Collection<LinkAddress> oLinks = mLinkProperties.getLinkAddresses();
+ Collection<LinkAddress> nLinks = newLp.getLinkAddresses();
+ for (LinkAddress oldLink : oLinks) {
+ for (LinkAddress newLink : nLinks) {
+ if ((NetworkUtils.addressTypeMatches(oldLink.getAddress(),
+ newLink.getAddress())) &&
+ (oldLink.equals(newLink) == false)) {
+ return DataConnectionAc.LinkPropertyChangeAction.RESET;
+ }
+ }
+ }
+
if (mLinkProperties == null || !mLinkProperties.equals(newLp)) {
mLinkProperties = newLp;
- changed = true;
+ changed = DataConnectionAc.LinkPropertyChangeAction.CHANGED;
}
return changed;
@@ -631,15 +611,14 @@
}
case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
DataCallState newState = (DataCallState) msg.obj;
- int updated = updateLinkProperty(newState) ? 1 : 0;
+ DataConnectionAc.LinkPropertyChangeAction action = updateLinkProperty(newState);
if (DBG) {
- log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE updated="
- + (updated == 1)
- + " newState=" + newState);
+ log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE action="
+ + action + " newState=" + newState);
}
mAc.replyToMessage(msg,
DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE,
- updated);
+ action.ordinal());
break;
}
case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
@@ -654,6 +633,11 @@
mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
transitionTo(mInactiveState);
break;
+ case DataConnectionAc.REQ_GET_REFCOUNT: {
+ log("REQ_GET_REFCOUNT refCount=" + mRefCount);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_REFCOUNT, mRefCount);
+ break;
+ }
case EVENT_CONNECT:
if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
@@ -754,9 +738,13 @@
break;
case EVENT_CONNECT:
- if (DBG) log("DcInactiveState msg.what=EVENT_CONNECT");
ConnectionParams cp = (ConnectionParams) msg.obj;
cp.tag = mTag;
+ if (DBG) {
+ log("DcInactiveState msg.what=EVENT_CONNECT." + "RefCount = "
+ + mRefCount);
+ }
+ mRefCount = 1;
onConnect(cp);
transitionTo(mActivatingState);
retVal = HANDLED;
@@ -784,7 +772,15 @@
switch (msg.what) {
case EVENT_DISCONNECT:
- if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT");
+ if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT"
+ + mRefCount);
+ deferMessage(msg);
+ retVal = HANDLED;
+ break;
+
+ case EVENT_CONNECT:
+ if (DBG) log("DcActivatingState deferring msg.what=EVENT_CONNECT refCount = "
+ + mRefCount);
deferMessage(msg);
retVal = HANDLED;
break;
@@ -908,12 +904,28 @@
boolean retVal;
switch (msg.what) {
+ case EVENT_CONNECT:
+ mRefCount++;
+ if (DBG) log("DcActiveState msg.what=EVENT_CONNECT RefCount=" + mRefCount);
+ if (msg.obj != null) {
+ notifyConnectCompleted((ConnectionParams) msg.obj, FailCause.NONE);
+ }
+ retVal = HANDLED;
+ break;
case EVENT_DISCONNECT:
- if (DBG) log("DcActiveState msg.what=EVENT_DISCONNECT");
- DisconnectParams dp = (DisconnectParams) msg.obj;
- dp.tag = mTag;
- tearDownData(dp);
- transitionTo(mDisconnectingState);
+ mRefCount--;
+ if (DBG) log("DcActiveState msg.what=EVENT_DISCONNECT RefCount=" + mRefCount);
+ if (mRefCount == 0)
+ {
+ DisconnectParams dp = (DisconnectParams) msg.obj;
+ dp.tag = mTag;
+ tearDownData(dp);
+ transitionTo(mDisconnectingState);
+ } else {
+ if (msg.obj != null) {
+ notifyDisconnectCompleted((DisconnectParams) msg.obj);
+ }
+ }
retVal = HANDLED;
break;
@@ -936,6 +948,13 @@
boolean retVal;
switch (msg.what) {
+ case EVENT_CONNECT:
+ if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = "
+ + mRefCount);
+ deferMessage(msg);
+ retVal = HANDLED;
+ break;
+
case EVENT_DEACTIVATE_DONE:
if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE");
AsyncResult ar = (AsyncResult) msg.obj;
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
index 2ab6184..a0d9b0f 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -59,6 +59,29 @@
public static final int REQ_RESET = BASE + 14;
public static final int RSP_RESET = BASE + 15;
+ public static final int REQ_GET_REFCOUNT = BASE + 16;
+ public static final int RSP_GET_REFCOUNT = BASE + 17;
+
+ /**
+ * enum used to notify action taken or necessary to be
+ * taken after the link property is changed.
+ */
+ public enum LinkPropertyChangeAction {
+ NONE, CHANGED, RESET;
+
+ public static LinkPropertyChangeAction fromInt(int value) {
+ if (value == NONE.ordinal()) {
+ return NONE;
+ } else if (value == CHANGED.ordinal()) {
+ return CHANGED;
+ } else if (value == RESET.ordinal()) {
+ return RESET;
+ } else {
+ throw new RuntimeException("LinkPropertyChangeAction.fromInt: bad value=" + value);
+ }
+ }
+ }
+
public DataConnectionAc(DataConnection dc, String logTag) {
dataConnection = dc;
mLogTag = logTag;
@@ -132,6 +155,40 @@
}
/**
+ * Request the Reference Count.
+ * Response {@link #rspRefCount}
+ */
+ public void reqRefCount() {
+ sendMessage(REQ_GET_REFCOUNT);
+ if (DBG) log("reqRefCount");
+ }
+
+ /**
+ * Evaluate a RSP_GET_REFCOUNT message and return the refCount.
+ *
+ * @param response Message
+ * @return ref count or -1 if an error
+ */
+ public int rspRefCount(Message response) {
+ int retVal = response.arg1;
+ if (DBG) log("rspRefCount=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * @return connection id or -1 if an error
+ */
+ public int getRefCountSync() {
+ Message response = sendMessageSynchronously(REQ_GET_REFCOUNT);
+ if ((response != null) && (response.what == RSP_GET_REFCOUNT)) {
+ return rspRefCount(response);
+ } else {
+ log("rspRefCount error response=" + response);
+ return -1;
+ }
+ }
+
+ /**
* Request the connections ApnSetting.
* Response {@link #rspApnSetting}
*/
@@ -234,8 +291,8 @@
if (DBG) log("reqUpdateLinkPropertiesDataCallState");
}
- public boolean rspUpdateLinkPropertiesDataCallState(Message response) {
- boolean retVal = response.arg1 == 1;
+ public LinkPropertyChangeAction rspUpdateLinkPropertiesDataCallState(Message response) {
+ LinkPropertyChangeAction retVal = LinkPropertyChangeAction.fromInt(response.arg1);
if (DBG) log("rspUpdateLinkPropertiesState=" + retVal);
return retVal;
}
@@ -245,7 +302,7 @@
*
* @return true if link property has been updated. false otherwise.
*/
- public boolean updateLinkPropertiesDataCallStateSync(DataCallState newState) {
+ public LinkPropertyChangeAction updateLinkPropertiesDataCallStateSync(DataCallState newState) {
Message response =
sendMessageSynchronously(REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, newState);
if ((response != null) &&
@@ -253,7 +310,7 @@
return rspUpdateLinkPropertiesDataCallState(response);
} else {
log("getLinkProperties error response=" + response);
- return false;
+ return LinkPropertyChangeAction.NONE;
}
}
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index b7ac879..5ddfcd1 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -987,7 +987,7 @@
resetAllRetryCounts();
onTrySetupData(Phone.REASON_DATA_ENABLED);
} else {
- onCleanUpConnection(true, APN_DEFAULT_ID, Phone.REASON_DATA_DISABLED);
+ onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 1b49d2d..a516b49 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -18,13 +18,20 @@
import static android.Manifest.permission.READ_PHONE_STATE;
import android.app.ActivityManagerNative;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
+import android.content.res.Resources;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
+import android.os.Power;
+import android.os.PowerManager;
import android.os.Registrant;
import android.os.RegistrantList;
import android.util.Log;
+import android.view.WindowManager;
import com.android.internal.telephony.PhoneBase;
import com.android.internal.telephony.CommandsInterface.RadioState;
@@ -32,6 +39,8 @@
import android.os.SystemProperties;
+import com.android.internal.R;
+
/**
* {@hide}
*/
@@ -88,6 +97,8 @@
private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
private static final int EVENT_ICC_STATUS_CHANGED = 12;
+ private static final int EVENT_CARD_REMOVED = 13;
+ private static final int EVENT_CARD_ADDED = 14;
/*
UNKNOWN is a transient state, for example, after uesr inputs ICC pin under
@@ -106,6 +117,11 @@
public boolean isPinLocked() {
return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
}
+
+ public boolean iccCardExist() {
+ return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED)
+ || (this == NETWORK_LOCKED) || (this == READY));
+ }
}
public State getState() {
@@ -400,6 +416,8 @@
boolean transitionedIntoPinLocked;
boolean transitionedIntoAbsent;
boolean transitionedIntoNetworkLocked;
+ boolean isIccCardRemoved;
+ boolean isIccCardAdded;
State oldState, newState;
@@ -416,24 +434,36 @@
transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
&& newState == State.NETWORK_LOCKED);
+ isIccCardRemoved = (oldState != null &&
+ oldState.iccCardExist() && newState == State.ABSENT);
+ isIccCardAdded = (oldState == State.ABSENT &&
+ newState != null && newState.iccCardExist());
if (transitionedIntoPinLocked) {
- if(mDbg) log("Notify SIM pin or puk locked.");
+ if (mDbg) log("Notify SIM pin or puk locked.");
mPinLockedRegistrants.notifyRegistrants();
broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
(newState == State.PIN_REQUIRED) ?
INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
} else if (transitionedIntoAbsent) {
- if(mDbg) log("Notify SIM missing.");
+ if (mDbg) log("Notify SIM missing.");
mAbsentRegistrants.notifyRegistrants();
broadcastIccStateChangedIntent(INTENT_VALUE_ICC_ABSENT, null);
} else if (transitionedIntoNetworkLocked) {
- if(mDbg) log("Notify SIM network locked.");
+ if (mDbg) log("Notify SIM network locked.");
mNetworkLockedRegistrants.notifyRegistrants();
broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
INTENT_VALUE_LOCKED_NETWORK);
}
+ if (isIccCardRemoved) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null));
+ } else if (isIccCardAdded) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null));
+ }
+
+
+
/*
* TODO: We need to try to remove this, maybe if the RIL sends up a RIL_UNSOL_SIM_REFRESH?
*/
@@ -443,6 +473,48 @@
((SIMRecords)mPhone.mIccRecords).onSimReady();
}
}
+
+ }
+
+ private void onIccSwap(boolean isAdded) {
+ // TODO: Here we assume the device can't handle SIM hot-swap
+ // and has to reboot. We may want to add a property,
+ // e.g. REBOOT_ON_SIM_SWAP, to indicate if modem support
+ // hot-swap.
+ DialogInterface.OnClickListener listener = null;
+
+
+ // TODO: SimRecords is not reset while SIM ABSENT (only reset while
+ // Radio_off_or_not_available). Have to reset in both both
+ // added or removed situation.
+ listener = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ if (mDbg) log("Reboot due to SIM swap");
+ PowerManager pm = (PowerManager) mPhone.getContext()
+ .getSystemService(Context.POWER_SERVICE);
+ pm.reboot("SIM is added.");
+ }
+ }
+
+ };
+
+ Resources r = Resources.getSystem();
+
+ String title = (isAdded) ? r.getString(R.string.sim_added_title) :
+ r.getString(R.string.sim_removed_title);
+ String message = (isAdded) ? r.getString(R.string.sim_added_message) :
+ r.getString(R.string.sim_removed_message);
+ String buttonTxt = r.getString(R.string.sim_restart_button);
+
+ AlertDialog dialog = new AlertDialog.Builder(mPhone.getContext())
+ .setTitle(title)
+ .setMessage(message)
+ .setPositiveButton(buttonTxt, listener)
+ .create();
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ dialog.show();
}
/**
@@ -609,6 +681,12 @@
Log.d(mLogTag, "Received Event EVENT_ICC_STATUS_CHANGED");
mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
break;
+ case EVENT_CARD_REMOVED:
+ onIccSwap(false);
+ break;
+ case EVENT_CARD_ADDED:
+ onIccSwap(true);
+ break;
default:
Log.e(mLogTag, "[IccCard] Unknown Event " + msg.what);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index f5d6c51..93fc9ce 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -113,6 +113,7 @@
/* Deactivate data call reasons */
int DEACTIVATE_REASON_NONE = 0;
int DEACTIVATE_REASON_RADIO_OFF = 1;
+ int DEACTIVATE_REASON_PDP_RESET = 2;
/*
cat include/telephony/ril.h | \
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 4927006..4309309 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -72,10 +72,12 @@
*/
static final String PROPERTY_OPERATOR_ISO_COUNTRY = "gsm.operator.iso-country";
- /** 'true' if device supports both LTE and CDMA mode of operation.
- * Availability: Set only on devices supporting LTE and CDMA.
+ /**
+ * The contents of this property is the value of the kernel command line
+ * product_type variable that corresponds to a product that supports LTE on CDMA.
+ * {@see BaseCommands#getLteOnCdmaMode()}
*/
- static final String PROPERTY_NETWORK_LTE_ON_CDMA = "telephony.lte_on_cdma";
+ static final String PROPERTY_LTE_ON_CDMA_PRODUCT_TYPE = "telephony.lteOnCdmaProductType";
static final String CURRENT_ACTIVE_PHONE = "gsm.current.phone-type";
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 375d0d1..e3e3d78 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -521,19 +521,7 @@
* TODO: Make this configurable?
*/
int nextReconnectDelay = mDataConnections.get(0).getRetryTimer();
- log("Data Connection activate failed. Scheduling next attempt for "
- + (nextReconnectDelay / 1000) + "s");
-
- AlarmManager am =
- (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
- Intent intent = new Intent(INTENT_RECONNECT_ALARM);
- intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason);
- mReconnectIntent = PendingIntent.getBroadcast(
- mPhone.getContext(), 0, intent, 0);
- am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + nextReconnectDelay,
- mReconnectIntent);
-
+ startAlarmForReconnect(nextReconnectDelay, reason);
mDataConnections.get(0).increaseRetryCount();
if (!shouldPostNotification(lastFailCauseCode)) {
@@ -545,6 +533,22 @@
}
}
+ private void startAlarmForReconnect(int delay, String reason) {
+
+ log("Data Connection activate failed. Scheduling next attempt for "
+ + (delay / 1000) + "s");
+
+ AlarmManager am =
+ (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
+ Intent intent = new Intent(INTENT_RECONNECT_ALARM);
+ intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason);
+ mReconnectIntent = PendingIntent.getBroadcast(
+ mPhone.getContext(), 0, intent, 0);
+ am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + delay, mReconnectIntent);
+
+ }
+
private void notifyNoData(FailCause lastFailCauseCode) {
setState(State.FAILED);
notifyDataAvailability(null);
@@ -702,7 +706,7 @@
mActiveApn = null;
if (retryAfterDisconnected(reason)) {
// Wait a bit before trying, so we're not tying up RIL command channel.
- sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS);
+ startAlarmForReconnect(APN_DELAY_MILLIS, reason);
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 6b4054a..e1a6fef 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -127,10 +127,7 @@
if (apnContext != null) {
apnContext.setReason(reason);
if (apnContext.getState() == State.FAILED) {
- Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
- msg.arg1 = 0; // tearDown is false
- msg.obj = (ApnContext)apnContext;
- sendMessage(msg);
+ apnContext.setState(State.IDLE);
}
sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext));
}
@@ -615,28 +612,26 @@
*
* @param apnContext
* @param tearDown
- * @return refCount
+ * @return none
*/
- private int releaseApnContext(ApnContext apnContext, boolean tearDown) {
+ private void releaseApnContext(ApnContext apnContext, boolean tearDown) {
if (apnContext == null) {
if (DBG) loge("releaseApnContext: apnContext null should not happen, ignore");
- return -1;
+ return;
}
DataConnection dc = apnContext.getDataConnection();
if (dc == null) {
if (DBG) loge("releaseApnContext: apnContext dc == null should not happen, ignore");
- return -1;
+ return;
}
- int refCount = dc.decAndGetRefCount();
- if (DBG) log("releaseApnContext: dec refCount=" + refCount + " tearDown=" + tearDown);
- if (tearDown && (refCount == 0)) {
+ if (tearDown) {
if (DBG) log("releaseApnContext: tearing down");
Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
}
apnContext.setDataConnection(null);
apnContext.setDataConnectionAc(null);
- return refCount;
+ return;
}
private void setupDataOnReadyApns(String reason) {
@@ -644,7 +639,7 @@
for (ApnContext apnContext : mApnContexts.values()) {
if (apnContext.isReady()) {
if (apnContext.getState() == State.FAILED) {
- cleanUpConnection(false, apnContext);
+ cleanApnContextBeforeRestart(apnContext);
if (apnContext.getDataConnection() != null) {
apnContext.getDataConnection().resetRetryCount();
}
@@ -800,6 +795,34 @@
if (DBG) {
log("cleanUpConnection: tearDown=" + tearDown + " reason=" + apnContext.getReason());
}
+ if (tearDown && cleanApnContextBeforeRestart(apnContext)) {
+ // if the request is tearDown and ApnContext does not hold an active connection,
+ // we're ok to return here.
+ return;
+ }
+
+ DataConnectionAc dcac = apnContext.getDataConnectionAc();
+ if (dcac != null) {
+ if (tearDown) {
+ apnContext.setState(State.DISCONNECTING);
+ releaseApnContext(apnContext, tearDown);
+ } else {
+ dcac.resetSync();
+ apnContext.setState(State.IDLE);
+ mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+ apnContext.setDataConnection(null);
+ apnContext.setDataConnectionAc(null);
+ }
+ }
+ }
+
+ /**
+ * @param APNContext to clean
+ * @return true if ApnContext is not connected anymore.
+ * false if ApnContext still holds a connection.
+ */
+ private boolean cleanApnContextBeforeRestart(ApnContext apnContext) {
+ if (apnContext == null) return true;
// Clear the reconnect alarm, if set.
if (apnContext.getReconnectIntent() != null) {
@@ -811,32 +834,16 @@
if (apnContext.getState() == State.IDLE || apnContext.getState() == State.DISCONNECTING) {
if (DBG) log("cleanUpConnection: state= " + apnContext.getState());
- return;
+ return true;
}
if (apnContext.getState() == State.FAILED) {
- if (DBG) log("cleanUpConnection: state is in FAILED");
apnContext.setState(State.IDLE);
- return;
+ return true;
}
-
- DataConnection conn = apnContext.getDataConnection();
- if (conn != null) {
- DataConnectionAc dcac = mDataConnectionAsyncChannels.get(conn.getDataConnectionId());
- apnContext.setState(State.DISCONNECTING);
- if (tearDown) {
- releaseApnContext(apnContext, tearDown);
- } else {
- if (dcac != null) {
- dcac.resetSync();
- }
- apnContext.setState(State.IDLE);
- mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
- }
- }
+ return false;
}
-
/**
* @param types comma delimited list of APN types
* @return array of APN types
@@ -927,37 +934,48 @@
return false;
}
- dc = findReadyDataConnection(apn);
+ // First, check to see if ApnContext already has DC.
+ // This could happen if the retries are currently engaged.
+ dc = (GsmDataConnection)apnContext.getDataConnection();
if (dc == null) {
- if (DBG) log("setupData: No ready GsmDataConnection found!");
- // TODO: When allocating you are mapping type to id. If more than 1 free,
- // then could findFreeDataConnection get the wrong one??
- dc = findFreeDataConnection();
- }
- if (dc == null) {
- dc = createDataConnection();
- }
+ dc = (GsmDataConnection) checkForConnectionForApnContext(apnContext);
- if (dc == null) {
- if (DBG) log("setupData: No free GsmDataConnection found!");
- return false;
- }
+ if (dc == null) {
+ dc = findReadyDataConnection(apn);
+ }
- dc.setProfileId( profileId );
- dc.setActiveApnType(apnContext.getApnType());
- int refCount = dc.incAndGetRefCount();
- if (DBG) log("setupData: init dc and apnContext refCount=" + refCount);
+ if (dc == null) {
+ if (DBG) log("setupData: No ready GsmDataConnection found!");
+ // TODO: When allocating you are mapping type to id. If more than 1 free,
+ // then could findFreeDataConnection get the wrong one??
+ dc = findFreeDataConnection();
+ }
- // configure retry count if no other Apn is using the same connection.
- if (refCount == 1) {
- configureRetry(dc, apnContext.getApnType());
+ if (dc == null) {
+ dc = createDataConnection();
+ }
+
+ if (dc == null) {
+ if (DBG) log("setupData: No free GsmDataConnection found!");
+ return false;
+ }
+
+ DataConnectionAc dcac = mDataConnectionAsyncChannels.get(dc.getDataConnectionId());
+ dc.setProfileId( profileId );
+ dc.setActiveApnType(apnContext.getApnType());
+ int refCount = dcac.getRefCountSync();
+ if (DBG) log("setupData: init dc and apnContext refCount=" + refCount);
+
+ // configure retry count if no other Apn is using the same connection.
+ if (refCount == 0) {
+ configureRetry(dc, apnContext.getApnType());
+ }
+ apnContext.setDataConnectionAc(mDataConnectionAsyncChannels.get(dc.getDataConnectionId()));
+ apnContext.setApnSetting(apn);
+ apnContext.setDataConnection(dc);
}
- DataConnectionAc dcac = mDataConnectionAsyncChannels.get(dc.getDataConnectionId());
- apnContext.setDataConnectionAc(mDataConnectionAsyncChannels.get(dc.getDataConnectionId()));
- apnContext.setApnSetting(apn);
- apnContext.setDataConnection(dc);
Message msg = obtainMessage();
msg.what = EVENT_DATA_SETUP_COMPLETE;
@@ -1053,25 +1071,37 @@
if (DBG) log("onDataStateChanged(ar): Found ConnId=" + connectionId
+ " newState=" + newState.toString());
if (newState.active != 0) {
- boolean changed
- = dcac.updateLinkPropertiesDataCallStateSync(newState);
- if (changed) {
+ boolean resetConnection;
+ switch (dcac.updateLinkPropertiesDataCallStateSync(newState)) {
+ case NONE:
+ if (DBG) log("onDataStateChanged(ar): Found but no change, skip");
+ resetConnection = false;
+ break;
+ case CHANGED:
if (DBG) log("onDataStateChanged(ar): Found and changed, notify");
mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED,
- apnContext.getApnType());
- // Temporary hack, if false we'll reset connections and at this
- // time a transition from CDMA -> Global fails. The DEACTIVATE
- // fails with a GENERIC_FAILURE and the VZWINTERNET connection is
- // never setup. @see bug/
+ apnContext.getApnType());
+ // Temporary hack, at this time a transition from CDMA -> Global
+ // fails so we'll hope for the best and not reset the connection.
+ // @see bug/4455071
if (SystemProperties.getBoolean("telephony.ignore-state-changes",
- true)) {
+ true)) {
log("onDataStateChanged(ar): STOPSHIP don't reset, continue");
- continue;
+ resetConnection = false;
+ } else {
+ // Things changed so reset connection, when hack is removed
+ // this is the normal path.
+ log("onDataStateChanged(ar): changed so resetting connection");
+ resetConnection = true;
}
- } else {
- if (DBG) log("onDataStateChanged(ar): Found but no change, skip");
- continue;
+ break;
+ case RESET:
+ default:
+ if (DBG) log("onDataStateChanged(ar): an error, reset connection");
+ resetConnection = true;
+ break;
}
+ if (resetConnection == false) continue;
}
}
@@ -1214,10 +1244,30 @@
preTxPkts = mTxPkts;
preRxPkts = mRxPkts;
- mTxPkts = TrafficStats.getMobileTxPackets();
- mRxPkts = TrafficStats.getMobileRxPackets();
+ long txSum = 0, rxSum = 0;
+ for (ApnContext apnContext : mApnContexts.values()) {
+ if (apnContext.getState() == State.CONNECTED) {
+ DataConnectionAc dcac = apnContext.getDataConnectionAc();
+ if (dcac == null) continue;
- //log("rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts));
+ LinkProperties linkProp = dcac.getLinkPropertiesSync();
+ if (linkProp == null) continue;
+
+ String iface = linkProp.getInterfaceName();
+
+ if (iface != null) {
+ long stats = TrafficStats.getTxPackets(iface);
+ if (stats > 0) txSum += stats;
+ stats = TrafficStats.getRxPackets(iface);
+ if (stats > 0) rxSum += stats;
+ }
+ }
+ }
+
+ mTxPkts = txSum;
+ mRxPkts = rxSum;
+
+ // log("tx " + mTxPkts + " rx " + mRxPkts);
if (mNetStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) {
sent = mTxPkts - preTxPkts;
@@ -1333,7 +1383,8 @@
loge("reconnectAfterFail: apnContext == null, impossible");
return;
}
- if (apnContext.getState() == State.FAILED) {
+ if ((apnContext.getState() == State.FAILED) &&
+ (apnContext.getDataConnection() != null)) {
if (!apnContext.getDataConnection().isRetryNeeded()) {
if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) {
mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
@@ -1353,23 +1404,7 @@
}
int nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();
- if (DBG) {
- log("reconnectAfterFail: activate failed. Scheduling next attempt for "
- + (nextReconnectDelay / 1000) + "s");
- }
-
- AlarmManager am =
- (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
- Intent intent = new Intent(INTENT_RECONNECT_ALARM);
- intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason());
- // Should put an extra of apn type?
- intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnContext.getApnType());
- apnContext.setReconnectIntent(PendingIntent.getBroadcast (
- mPhone.getContext(), 0, intent, 0));
- am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + nextReconnectDelay,
- apnContext.getReconnectIntent());
-
+ startAlarmForReconnect(nextReconnectDelay, apnContext);
apnContext.getDataConnection().increaseRetryCount();
if (!shouldPostNotification(lastFailCauseCode)) {
@@ -1383,6 +1418,25 @@
}
}
+ private void startAlarmForReconnect(int delay, ApnContext apnContext) {
+
+ if (DBG) {
+ log("Schedule alarm for reconnect: activate failed. Scheduling next attempt for "
+ + (delay / 1000) + "s");
+ }
+
+ AlarmManager am =
+ (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
+ Intent intent = new Intent(INTENT_RECONNECT_ALARM);
+ intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason());
+ intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnContext.getApnType());
+ apnContext.setReconnectIntent(PendingIntent.getBroadcast (
+ mPhone.getContext(), 0, intent, 0));
+ am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + delay, apnContext.getReconnectIntent());
+
+ }
+
private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode,
ApnContext apnContext) {
if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
@@ -1437,23 +1491,10 @@
} else {
apnContext.setReason(Phone.REASON_DATA_ENABLED);
}
- DataConnection conn = checkForConnectionForApnContext(apnContext);
- if (conn == null) {
- if (apnContext.getState() == State.FAILED) {
- apnContext.setState(State.IDLE);
- }
- trySetup = true;
- } else {
- int refCount = conn.incAndGetRefCount();
- apnContext.setDataConnection(conn);
- apnContext.setDataConnectionAc(
- mDataConnectionAsyncChannels.get(conn.getDataConnectionId()));
- if (DBG) {
- log("applyNewState: Found existing connection for " +
- apnContext.getApnType() + " inc refCount=" + refCount +
- " conn=" + conn);
- }
+ if (apnContext.getState() == State.FAILED) {
+ apnContext.setState(State.IDLE);
}
+ trySetup = true;
}
}
apnContext.setEnabled(enabled);
@@ -1588,7 +1629,7 @@
if (DBG) {
log(String.format("onDataSetupComplete: success apn=%s",
- apnContext.getWaitingApns().get(0).apn) + " refCount=" + dc.getRefCount());
+ apnContext.getWaitingApns().get(0).apn));
}
ApnSetting apn = apnContext.getApnSetting();
if (apn.proxy != null && apn.proxy.length() != 0) {
@@ -1655,6 +1696,11 @@
}
apnContext.setState(State.FAILED);
mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
+
+ releaseApnContext(apnContext, false);
+ if (DBG) {
+ log("onDataSetupComplete: permanent error apn=%s" + apnString );
+ }
} else {
if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");
startDelayedRetry(cause, apnContext);
@@ -1664,13 +1710,7 @@
apnContext.setState(State.SCANNING);
// Wait a bit before trying the next APN, so that
// we're not tying up the RIL command channel
- sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext),
- APN_DELAY_MILLIS);
- }
-
- int refCount = releaseApnContext(apnContext, false);
- if (DBG) {
- log("onDataSetupComplete: error apn=%s" + apnString + " refCount=" + refCount);
+ startAlarmForReconnect(APN_DELAY_MILLIS, apnContext);
}
}
}
@@ -1710,7 +1750,7 @@
// Wait a bit before trying the next APN, so that
// we're not tying up the RIL command channel.
// This also helps in any external dependency to turn off the context.
- sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext),APN_DELAY_MILLIS);
+ startAlarmForReconnect(APN_DELAY_MILLIS, apnContext);
}
}
@@ -1753,7 +1793,10 @@
protected void onCleanUpConnection(boolean tearDown, int apnId, String reason) {
if (DBG) log("onCleanUpConnection");
ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
- cleanUpConnection(tearDown, apnContext);
+ if (apnContext != null) {
+ apnContext.setReason(reason);
+ cleanUpConnection(tearDown, apnContext);
+ }
}
protected boolean isConnected() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index b7b0af3..643f709 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -50,6 +50,7 @@
if(mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE) {
mPhone.mCM.registerForNVReady(mHandler, EVENT_ICC_READY, null);
+ mPhone.mCM.registerForIccStatusChanged(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null);
}
}
@@ -60,6 +61,11 @@
mPhone.mCM.unregisterForSIMLockedOrAbsent(mHandler);
mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
mPhone.mCM.unregisterForSIMReady(mHandler);
+
+ if(mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE) {
+ mPhone.mCM.unregisterForNVReady(mHandler);
+ mPhone.mCM.unregisterForIccStatusChanged(mHandler);
+ }
}
@Override