Merge "Added missing comments in Instrumentation#sendStringSync"
diff --git a/api/current.txt b/api/current.txt
index 37b888e..1bd2c09 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10696,6 +10696,7 @@
field public static final int METADATA_KEY_GENRE = 6; // 0x6
field public static final int METADATA_KEY_HAS_AUDIO = 16; // 0x10
field public static final int METADATA_KEY_HAS_VIDEO = 17; // 0x11
+ field public static final int METADATA_KEY_LOCATION = 23; // 0x17
field public static final int METADATA_KEY_MIMETYPE = 12; // 0xc
field public static final int METADATA_KEY_NUM_TRACKS = 10; // 0xa
field public static final int METADATA_KEY_TITLE = 7; // 0x7
@@ -18892,7 +18893,8 @@
method public int playSilence(long, int, java.util.HashMap<java.lang.String, java.lang.String>);
method public deprecated int setEngineByPackageName(java.lang.String);
method public int setLanguage(java.util.Locale);
- method public int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
+ method public deprecated int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
+ method public int setOnUtteranceProgressListener(android.speech.tts.UtteranceProgressListener);
method public int setPitch(float);
method public int setSpeechRate(float);
method public void shutdown();
@@ -18965,6 +18967,13 @@
method protected abstract void onSynthesizeText(android.speech.tts.SynthesisRequest, android.speech.tts.SynthesisCallback);
}
+ public abstract class UtteranceProgressListener {
+ ctor public UtteranceProgressListener();
+ method public abstract void onDone(java.lang.String);
+ method public abstract void onError(java.lang.String);
+ method public abstract void onStart(java.lang.String);
+ }
+
}
package android.telephony {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index d816e7c..154dbb8 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -42,6 +42,7 @@
#include <surfaceflinger/ISurfaceComposerClient.h>
#include <core/SkBitmap.h>
+#include <core/SkStream.h>
#include <images/SkImageDecoder.h>
#include <GLES/gl.h>
@@ -150,9 +151,15 @@
//StopWatch watch("blah");
SkBitmap bitmap;
- SkImageDecoder::DecodeMemory(buffer, len,
- &bitmap, SkBitmap::kRGB_565_Config,
- SkImageDecoder::kDecodePixels_Mode);
+ SkMemoryStream stream(buffer, len);
+ SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
+ codec->setDitherImage(false);
+ if (codec) {
+ codec->decode(&stream, &bitmap,
+ SkBitmap::kRGB_565_Config,
+ SkImageDecoder::kDecodePixels_Mode);
+ delete codec;
+ }
// ensure we can call getPixels(). No need to call unlock, since the
// bitmap will go out of scope when we return from this method.
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index ca66a4e..1e746cd 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -63,6 +63,7 @@
printf("\n");
printf("Build: %s\n", build);
+ printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
printf("Bootloader: %s\n", bootloader);
printf("Radio: %s\n", radio);
printf("Network: %s\n", network);
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index f383af9..7f0ea99 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -657,6 +657,15 @@
*/
private void setupChangeAnimation(final ViewGroup parent, final int changeReason,
Animator baseAnimator, final long duration, final View child) {
+
+ // If we already have a listener for this child, then we've already set up the
+ // changing animation we need. Multiple calls for a child may occur when several
+ // add/remove operations are run at once on a container; each one will trigger
+ // changes for the existing children in the container.
+ if (layoutChangeListenerMap.get(child) != null) {
+ return;
+ }
+
// Make a copy of the appropriate animation
final Animator anim = baseAnimator.clone();
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 522f477..0c6baeb 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -901,6 +901,7 @@
private RuntimeException mUnbindLocation;
private boolean mDied;
+ private boolean mForgotten;
private static class ConnectionInfo {
IBinder binder;
@@ -959,6 +960,7 @@
ci.binder.unlinkToDeath(ci.deathMonitor, 0);
}
mActiveConnections.clear();
+ mForgotten = true;
}
}
@@ -1020,6 +1022,11 @@
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
+ if (mForgotten) {
+ // We unbound before receiving the connection; ignore
+ // any connection received.
+ return;
+ }
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
// Huh, already have this one. Oh well!
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index f81ea81..91398bc 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -212,7 +212,11 @@
*/
mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER);
}
-
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
synchronized (this) {
if (mWallpaper != null) {
@@ -604,7 +608,7 @@
// Ignore
}
}
-
+
/**
* Set the position of the current wallpaper within any larger space, when
* that wallpaper is visible behind the given window. The X and Y offsets
@@ -619,16 +623,23 @@
* @param yOffset The offset along the Y dimension, from 0 to 1.
*/
public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
- try {
- //Log.v(TAG, "Sending new wallpaper offsets from app...");
- ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
- windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
- //Log.v(TAG, "...app returning after sending offsets!");
- } catch (RemoteException e) {
- // Ignore.
- }
+ final IBinder fWindowToken = windowToken;
+ final float fXOffset = xOffset;
+ final float fYOffset = yOffset;
+ sGlobals.getHandler().post(new Runnable() {
+ public void run() {
+ try {
+ //Log.v(TAG, "Sending new wallpaper offsets from app...");
+ ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ fWindowToken, fXOffset, fYOffset, mWallpaperXStep, mWallpaperYStep);
+ //Log.v(TAG, "...app returning after sending offsets!");
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ }
+ });
}
-
+
/**
* For applications that use multiple virtual screens showing a wallpaper,
* specify the step size between virtual screens. For example, if the
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 7addd4a..b1d0070 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -86,7 +86,7 @@
private static final int CONNECTION_ACCESS_REQUEST_REPLY = 104;
private static final int CONNECTION_ACCESS_REQUEST_EXPIRY = 105;
- private static final int CONNECT_OTHER_PROFILES_DELAY = 4000; // 4 secs
+ public static final int CONNECT_OTHER_PROFILES_DELAY = 4000; // 4 secs
private static final int CONNECTION_ACCESS_REQUEST_EXPIRY_TIMEOUT = 7000; // 7 secs
private static final int CONNECTION_ACCESS_UNDEFINED = -1;
private static final long INIT_INCOMING_REJECT_TIMER = 1000; // 1 sec
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index fefeb93..deea2b8 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -90,7 +90,7 @@
boolean connectHeadset(String address);
boolean disconnectHeadset(String address);
- boolean notifyIncomingConnection(String address);
+ boolean notifyIncomingConnection(String address, boolean rejected);
// HID profile APIs
boolean connectInputDevice(in BluetoothDevice device);
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index ad1bfb2..bea6529 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -484,7 +484,7 @@
private final AssetManager mAssets;
private final int mNative;
- private final StringBlock mStrings;
+ /*package*/ final StringBlock mStrings;
private boolean mOpen = true;
private int mOpenCount = 1;
@@ -494,9 +494,9 @@
private static final native int nativeGetStringBlock(int obj);
private static final native int nativeCreateParseState(int obj);
- private static final native int nativeNext(int state);
+ /*package*/ static final native int nativeNext(int state);
private static final native int nativeGetNamespace(int state);
- private static final native int nativeGetName(int state);
+ /*package*/ static final native int nativeGetName(int state);
private static final native int nativeGetText(int state);
private static final native int nativeGetLineNumber(int state);
private static final native int nativeGetAttributeCount(int state);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 0052dd0..a569317 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -360,6 +360,11 @@
}
}
+ /**
+ * Gets you info about the current data network.
+ * Call {@link NetworkInfo#isConnected()} on the returned {@link NetworkInfo}
+ * to check if the device has a data connection.
+ */
public NetworkInfo getActiveNetworkInfo() {
try {
return mService.getActiveNetworkInfo();
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 537750a..7286f0d 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -22,8 +22,9 @@
import java.util.EnumMap;
/**
- * Describes the status of a network interface of a given type
- * (currently either Mobile or Wifi).
+ * Describes the status of a network interface.
+ * <p>Use {@link ConnectivityManager#getActiveNetworkInfo()} to get an instance that represents
+ * the current network connection.
*/
public class NetworkInfo implements Parcelable {
@@ -38,7 +39,7 @@
* <tr><td><code>SCANNING</code></td><td><code>CONNECTING</code></td></tr>
* <tr><td><code>CONNECTING</code></td><td><code>CONNECTING</code></td></tr>
* <tr><td><code>AUTHENTICATING</code></td><td><code>CONNECTING</code></td></tr>
- * <tr><td><code>CONNECTED</code></td><td<code>CONNECTED</code></td></tr>
+ * <tr><td><code>CONNECTED</code></td><td><code>CONNECTED</code></td></tr>
* <tr><td><code>DISCONNECTING</code></td><td><code>DISCONNECTING</code></td></tr>
* <tr><td><code>DISCONNECTED</code></td><td><code>DISCONNECTED</code></td></tr>
* <tr><td><code>UNAVAILABLE</code></td><td><code>DISCONNECTED</code></td></tr>
@@ -159,9 +160,12 @@
}
/**
- * Reports the type of network (currently mobile or Wi-Fi) to which the
- * info in this object pertains.
- * @return the network type
+ * Reports the type of network to which the
+ * info in this {@code NetworkInfo} pertains.
+ * @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link
+ * ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link
+ * ConnectivityManager#TYPE_ETHERNET}, {@link ConnectivityManager#TYPE_BLUETOOTH}, or other
+ * types defined by {@link ConnectivityManager}
*/
public int getType() {
synchronized (this) {
@@ -226,6 +230,7 @@
/**
* Indicates whether network connectivity exists and it is possible to establish
* connections and pass data.
+ * <p>Always call this before attempting to perform data transactions.
* @return {@code true} if network connectivity exists, {@code false} otherwise.
*/
public boolean isConnected() {
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 3605652..f6e627c 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -464,6 +464,19 @@
* time, and that none of them have disappeared.
*/
public NetworkStats subtract(NetworkStats value) throws NonMonotonicException {
+ return subtract(value, false);
+ }
+
+ /**
+ * 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.
+ *
+ * @param clampNonMonotonic When non-monotonic stats are found, just clamp
+ * to 0 instead of throwing {@link NonMonotonicException}.
+ */
+ public NetworkStats subtract(NetworkStats value, boolean clampNonMonotonic)
+ throws NonMonotonicException {
final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime;
if (deltaRealtime < 0) {
throw new NonMonotonicException(this, value);
@@ -497,7 +510,15 @@
if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
|| entry.txPackets < 0 || entry.operations < 0) {
- throw new NonMonotonicException(this, i, value, j);
+ if (clampNonMonotonic) {
+ entry.rxBytes = Math.max(entry.rxBytes, 0);
+ entry.rxPackets = Math.max(entry.rxPackets, 0);
+ entry.txBytes = Math.max(entry.txBytes, 0);
+ entry.txPackets = Math.max(entry.txPackets, 0);
+ entry.operations = Math.max(entry.operations, 0);
+ } else {
+ throw new NonMonotonicException(this, i, value, j);
+ }
}
}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 3a2bbec..0fb49bc 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1645,6 +1645,9 @@
/**
* Searches the query string for the first value with the given key.
*
+ * <p><strong>Warning:</strong> Prior to Ice Cream Sandwich, this decoded
+ * the '+' character as '+' rather than ' '.
+ *
* @param key which will be encoded
* @throws UnsupportedOperationException if this isn't a hierarchical URI
* @throws NullPointerException if key is null
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 016af58..0b93ad0 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -32,7 +32,7 @@
interface INfcAdapter
{
INfcTag getNfcTagInterface();
- INfcAdapterExtras getNfcAdapterExtrasInterface();
+ INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
int getState();
boolean disable();
diff --git a/core/java/android/nfc/INfcAdapterExtras.aidl b/core/java/android/nfc/INfcAdapterExtras.aidl
index 0c2a2fd..2b9d4f0 100644
--- a/core/java/android/nfc/INfcAdapterExtras.aidl
+++ b/core/java/android/nfc/INfcAdapterExtras.aidl
@@ -23,10 +23,10 @@
* {@hide}
*/
interface INfcAdapterExtras {
- Bundle open(IBinder b);
- Bundle close();
- Bundle transceive(in byte[] data_in);
- int getCardEmulationRoute();
- void setCardEmulationRoute(int route);
- void authenticate(in byte[] token);
+ Bundle open(in String pkg, IBinder b);
+ Bundle close(in String pkg, IBinder b);
+ Bundle transceive(in String pkg, in byte[] data_in);
+ int getCardEmulationRoute(in String pkg);
+ void setCardEmulationRoute(in String pkg, int route);
+ void authenticate(in String pkg, in byte[] token);
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index f2bccaa..dec262b 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -16,6 +16,8 @@
package android.nfc;
+import java.util.HashMap;
+
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Activity;
@@ -197,15 +199,21 @@
static INfcTag sTagService;
/**
- * NfcAdapter is currently a singleton, and does not require a context.
- * However all the public API's are future-proofed to require a context.
- * If we start using that then we'll need to keep a HashMap of
- * Context.getApplicationContext() -> NfcAdapter, such that NfcAdapter
- * is a singleton within each application context.
+ * The NfcAdapter object for each application context.
+ * There is a 1-1 relationship between application context and
+ * NfcAdapter object.
*/
- static NfcAdapter sSingleton; // protected by NfcAdapter.class
+ static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class
+
+ /**
+ * NfcAdapter used with a null context. This ctor was deprecated but we have
+ * to support it for backwards compatibility. New methods that require context
+ * might throw when called on the null-context NfcAdapter.
+ */
+ static NfcAdapter sNullContextNfcAdapter; // protected by NfcAdapter.class
final NfcActivityManager mNfcActivityManager;
+ final Context mContext;
/**
* A callback to be invoked when the system successfully delivers your {@link NdefMessage}
@@ -280,12 +288,12 @@
}
/**
- * Returns the singleton, or throws if NFC is not available.
+ * Returns the NfcAdapter for application context,
+ * or throws if NFC is not available.
+ * @hide
*/
- static synchronized NfcAdapter getSingleton() {
+ public static synchronized NfcAdapter getNfcAdapter(Context context) {
if (!sIsInitialized) {
- sIsInitialized = true;
-
/* is this device meant to have NFC */
if (!hasNfcFeature()) {
Log.v(TAG, "this device does not have NFC support");
@@ -303,12 +311,21 @@
Log.e(TAG, "could not retrieve NFC Tag service");
throw new UnsupportedOperationException();
}
- sSingleton = new NfcAdapter();
+
+ sIsInitialized = true;
}
- if (sSingleton == null) {
- throw new UnsupportedOperationException();
+ if (context == null) {
+ if (sNullContextNfcAdapter == null) {
+ sNullContextNfcAdapter = new NfcAdapter(null);
+ }
+ return sNullContextNfcAdapter;
}
- return sSingleton;
+ NfcAdapter adapter = sNfcAdapters.get(context);
+ if (adapter == null) {
+ adapter = new NfcAdapter(context);
+ sNfcAdapters.put(context, adapter);
+ }
+ return adapter;
}
/** get handle to NFC service interface */
@@ -336,6 +353,10 @@
* @return the default NFC adapter, or null if no NFC adapter exists
*/
public static NfcAdapter getDefaultAdapter(Context context) {
+ if (context == null) {
+ throw new IllegalArgumentException("context cannot be null");
+ }
+ context = context.getApplicationContext();
/* use getSystemService() instead of just instantiating to take
* advantage of the context's cached NfcManager & NfcAdapter */
NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
@@ -343,25 +364,30 @@
}
/**
- * Get a handle to the default NFC Adapter on this Android device.
- * <p>
- * Most Android devices will only have one NFC Adapter (NFC Controller).
- *
- * @return the default NFC adapter, or null if no NFC adapter exists
+ * Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p>
+ * This method was deprecated at API level 10 (Gingerbread MR1) because a context is required
+ * for many NFC API methods. Those methods will fail when called on an NfcAdapter
+ * object created from this method.<p>
* @deprecated use {@link #getDefaultAdapter(Context)}
*/
@Deprecated
public static NfcAdapter getDefaultAdapter() {
Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
"NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
- return getSingleton();
+
+ return NfcAdapter.getNfcAdapter(null);
+ }
+
+ NfcAdapter(Context context) {
+ mContext = context;
+ mNfcActivityManager = new NfcActivityManager(this);
}
/**
- * Does not currently need a context.
+ * @hide
*/
- NfcAdapter() {
- mNfcActivityManager = new NfcActivityManager(this);
+ public Context getContext() {
+ return mContext;
}
/**
@@ -834,8 +860,12 @@
* @hide
*/
public INfcAdapterExtras getNfcAdapterExtrasInterface() {
+ if (mContext == null) {
+ throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
+ + " NFC extras APIs");
+ }
try {
- return sService.getNfcAdapterExtrasInterface();
+ return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
return null;
diff --git a/core/java/android/nfc/NfcManager.java b/core/java/android/nfc/NfcManager.java
index 300ab45..6ec2e21 100644
--- a/core/java/android/nfc/NfcManager.java
+++ b/core/java/android/nfc/NfcManager.java
@@ -39,8 +39,9 @@
*/
public NfcManager(Context context) {
NfcAdapter adapter;
+ context = context.getApplicationContext();
try {
- adapter = NfcAdapter.getSingleton();
+ adapter = NfcAdapter.getNfcAdapter(context);
} catch (UnsupportedOperationException e) {
adapter = null;
}
diff --git a/core/java/android/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java
index da7c489..c59a05a 100644
--- a/core/java/android/server/BluetoothAdapterStateMachine.java
+++ b/core/java/android/server/BluetoothAdapterStateMachine.java
@@ -62,6 +62,17 @@
* m1 = TURN_HOT
* m2 = Transition to HotOff when number of process wanting BT on is 0.
* POWER_STATE_CHANGED will make the transition.
+ * Note:
+ * The diagram above shows all the states and messages that trigger normal state changes.
+ * The diagram above does not capture everything:
+ * The diagram does not capture following messages.
+ * - messages that do not trigger state changes
+ * For example, PER_PROCESS_TURN_ON received in BluetoothOn state
+ * - unhandled messages
+ * For example, USER_TURN_ON received in BluetoothOn state
+ * - timeout messages
+ * The diagram does not capture error conditions and state recoveries.
+ * - For example POWER_STATE_CHANGED received in BluetoothOn state
*/
final class BluetoothAdapterStateMachine extends StateMachine {
private static final String TAG = "BluetoothAdapterStateMachine";
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 1b473ec..aa62cd7 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -784,11 +784,12 @@
// machine. We don't handle AVCTP signals currently. We only send
// intents for AVDTP state changes. We need to handle both of them in
// some cases. For now, just don't move to incoming state in this case.
- mBluetoothService.notifyIncomingA2dpConnection(address);
+ mBluetoothService.notifyIncomingA2dpConnection(address, true);
} else {
Log.i(TAG, "" + authorized +
"Incoming A2DP / AVRCP connection from " + address);
mA2dp.allowIncomingConnect(device, authorized);
+ mBluetoothService.notifyIncomingA2dpConnection(address, false);
}
} else if (BluetoothUuid.isInputDevice(uuid)) {
// We can have more than 1 input device connected.
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 9ca5847..d604a01 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -89,7 +89,7 @@
private int mNativeData;
private BluetoothEventLoop mEventLoop;
- private BluetoothHeadset mBluetoothHeadset;
+ private BluetoothHeadset mHeadsetProxy;
private BluetoothInputDevice mInputDevice;
private BluetoothPan mPan;
private boolean mIsAirplaneSensitive;
@@ -605,6 +605,7 @@
}
mBondState.initBondState();
initProfileState();
+ getProfileProxy();
}
/**
@@ -1766,8 +1767,8 @@
private void dumpHeadsetService(PrintWriter pw) {
pw.println("\n--Headset Service--");
- if (mBluetoothHeadset != null) {
- List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
+ if (mHeadsetProxy != null) {
+ List<BluetoothDevice> deviceList = mHeadsetProxy.getConnectedDevices();
if (deviceList.size() == 0) {
pw.println("No headsets connected");
} else {
@@ -1775,21 +1776,20 @@
pw.println("\ngetConnectedDevices[0] = " + device);
dumpHeadsetConnectionState(pw, device);
pw.println("getBatteryUsageHint() = " +
- mBluetoothHeadset.getBatteryUsageHint(device));
+ mHeadsetProxy.getBatteryUsageHint(device));
}
deviceList.clear();
- deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] {
+ deviceList = mHeadsetProxy.getDevicesMatchingConnectionStates(new int[] {
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
pw.println("--Connected and Disconnected Headsets");
for (BluetoothDevice device: deviceList) {
pw.println(device);
- if (mBluetoothHeadset.isAudioConnected(device)) {
+ if (mHeadsetProxy.isAudioConnected(device)) {
pw.println("SCO audio connected to device:" + device);
}
}
}
- mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
}
private void dumpInputDeviceProfile(PrintWriter pw) {
@@ -1824,7 +1824,6 @@
pw.println(device);
}
}
- mAdapter.closeProfileProxy(BluetoothProfile.INPUT_DEVICE, mBluetoothHeadset);
}
private void dumpPanProfile(PrintWriter pw) {
@@ -1862,7 +1861,7 @@
private void dumpHeadsetConnectionState(PrintWriter pw,
BluetoothDevice device) {
- switch (mBluetoothHeadset.getConnectionState(device)) {
+ switch (mHeadsetProxy.getConnectionState(device)) {
case BluetoothHeadset.STATE_CONNECTING:
pw.println("getConnectionState() = STATE_CONNECTING");
break;
@@ -1884,7 +1883,6 @@
Integer pid = mServiceRecordToPid.get(handle).first;
pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
}
- mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothHeadset);
}
private void dumpAclConnectedDevices(PrintWriter pw) {
@@ -1927,11 +1925,16 @@
}
}
+ private void getProfileProxy() {
+ mAdapter.getProfileProxy(mContext,
+ mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
+ }
+
private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
- mBluetoothHeadset = (BluetoothHeadset) proxy;
+ mHeadsetProxy = (BluetoothHeadset) proxy;
} else if (profile == BluetoothProfile.INPUT_DEVICE) {
mInputDevice = (BluetoothInputDevice) proxy;
} else if (profile == BluetoothProfile.PAN) {
@@ -1940,7 +1943,7 @@
}
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.HEADSET) {
- mBluetoothHeadset = null;
+ mHeadsetProxy = null;
} else if (profile == BluetoothProfile.INPUT_DEVICE) {
mInputDevice = null;
} else if (profile == BluetoothProfile.PAN) {
@@ -2424,25 +2427,43 @@
}
}
- public boolean notifyIncomingConnection(String address) {
- BluetoothDeviceProfileState state =
- mDeviceProfileState.get(address);
+ public boolean notifyIncomingConnection(String address, boolean rejected) {
+ BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
if (state != null) {
Message msg = new Message();
- msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
- state.sendMessage(msg);
+ if (rejected) {
+ if (mA2dpService.getPriority(getRemoteDevice(address)) >=
+ BluetoothProfile.PRIORITY_ON) {
+ msg.what = BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES;
+ msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
+ state.sendMessageDelayed(msg,
+ BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES_DELAY);
+ }
+ } else {
+ msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
+ state.sendMessage(msg);
+ }
return true;
}
return false;
}
- /*package*/ boolean notifyIncomingA2dpConnection(String address) {
- BluetoothDeviceProfileState state =
- mDeviceProfileState.get(address);
+ /*package*/ boolean notifyIncomingA2dpConnection(String address, boolean rejected) {
+ BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
if (state != null) {
Message msg = new Message();
- msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
- state.sendMessage(msg);
+ if (rejected) {
+ if (mHeadsetProxy.getPriority(getRemoteDevice(address)) >=
+ BluetoothProfile.PRIORITY_ON) {
+ msg.what = BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES;
+ msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
+ state.sendMessageDelayed(msg,
+ BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES_DELAY);
+ }
+ } else {
+ msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
+ state.sendMessage(msg);
+ }
return true;
}
return false;
diff --git a/core/java/android/speech/tts/AudioMessageParams.java b/core/java/android/speech/tts/AudioMessageParams.java
index 68d8738..29b4367 100644
--- a/core/java/android/speech/tts/AudioMessageParams.java
+++ b/core/java/android/speech/tts/AudioMessageParams.java
@@ -15,12 +15,12 @@
*/
package android.speech.tts;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
class AudioMessageParams extends MessageParams {
private final BlockingMediaPlayer mPlayer;
- AudioMessageParams(UtteranceCompletedDispatcher dispatcher,
+ AudioMessageParams(UtteranceProgressDispatcher dispatcher,
String callingApp, BlockingMediaPlayer player) {
super(dispatcher, callingApp);
mPlayer = player;
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index d970ae6..0194240 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -312,10 +312,11 @@
private void handleSilence(MessageParams msg) {
if (DBG) Log.d(TAG, "handleSilence()");
SilenceMessageParams params = (SilenceMessageParams) msg;
+ params.getDispatcher().dispatchOnStart();
if (params.getSilenceDurationMs() > 0) {
params.getConditionVariable().block(params.getSilenceDurationMs());
}
- params.getDispatcher().dispatchUtteranceCompleted();
+ params.getDispatcher().dispatchOnDone();
if (DBG) Log.d(TAG, "handleSilence() done.");
}
@@ -323,11 +324,12 @@
private void handleAudio(MessageParams msg) {
if (DBG) Log.d(TAG, "handleAudio()");
AudioMessageParams params = (AudioMessageParams) msg;
+ params.getDispatcher().dispatchOnStart();
// Note that the BlockingMediaPlayer spawns a separate thread.
//
// TODO: This can be avoided.
params.getPlayer().startAndWait();
- params.getDispatcher().dispatchUtteranceCompleted();
+ params.getDispatcher().dispatchOnDone();
if (DBG) Log.d(TAG, "handleAudio() done.");
}
@@ -361,6 +363,7 @@
if (DBG) Log.d(TAG, "Created audio track [" + audioTrack.hashCode() + "]");
param.setAudioTrack(audioTrack);
+ msg.getDispatcher().dispatchOnStart();
}
// More data available to be flushed to the audio track.
@@ -411,6 +414,7 @@
final AudioTrack audioTrack = params.getAudioTrack();
if (audioTrack == null) {
+ params.getDispatcher().dispatchOnError();
return;
}
@@ -439,7 +443,7 @@
audioTrack.release();
params.setAudioTrack(null);
}
- params.getDispatcher().dispatchUtteranceCompleted();
+ params.getDispatcher().dispatchOnDone();
mLastSynthesisRequest = null;
params.mLogger.onWriteData();
}
diff --git a/core/java/android/speech/tts/ITextToSpeechCallback.aidl b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
index 40902ae..f0287d4 100755
--- a/core/java/android/speech/tts/ITextToSpeechCallback.aidl
+++ b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
@@ -21,5 +21,7 @@
* {@hide}
*/
oneway interface ITextToSpeechCallback {
- void utteranceCompleted(String utteranceId);
+ void onStart(String utteranceId);
+ void onDone(String utteranceId);
+ void onError(String utteranceId);
}
diff --git a/core/java/android/speech/tts/MessageParams.java b/core/java/android/speech/tts/MessageParams.java
index e7d6da3..de9cc07 100644
--- a/core/java/android/speech/tts/MessageParams.java
+++ b/core/java/android/speech/tts/MessageParams.java
@@ -15,22 +15,22 @@
*/
package android.speech.tts;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
abstract class MessageParams {
static final int TYPE_SYNTHESIS = 1;
static final int TYPE_AUDIO = 2;
static final int TYPE_SILENCE = 3;
- private final UtteranceCompletedDispatcher mDispatcher;
+ private final UtteranceProgressDispatcher mDispatcher;
private final String mCallingApp;
- MessageParams(UtteranceCompletedDispatcher dispatcher, String callingApp) {
+ MessageParams(UtteranceProgressDispatcher dispatcher, String callingApp) {
mDispatcher = dispatcher;
mCallingApp = callingApp;
}
- UtteranceCompletedDispatcher getDispatcher() {
+ UtteranceProgressDispatcher getDispatcher() {
return mDispatcher;
}
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index 0cca06a..ce3522b 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -15,7 +15,7 @@
*/
package android.speech.tts;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
import android.util.Log;
/**
@@ -62,12 +62,12 @@
private volatile boolean mDone = false;
- private final UtteranceCompletedDispatcher mDispatcher;
+ private final UtteranceProgressDispatcher mDispatcher;
private final String mCallingApp;
private final EventLogger mLogger;
PlaybackSynthesisCallback(int streamType, float volume, float pan,
- AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher,
+ AudioPlaybackHandler audioTrackHandler, UtteranceProgressDispatcher dispatcher,
String callingApp, EventLogger logger) {
mStreamType = streamType;
mVolume = volume;
diff --git a/core/java/android/speech/tts/SilenceMessageParams.java b/core/java/android/speech/tts/SilenceMessageParams.java
index 7a4ff1c..9909126 100644
--- a/core/java/android/speech/tts/SilenceMessageParams.java
+++ b/core/java/android/speech/tts/SilenceMessageParams.java
@@ -16,13 +16,13 @@
package android.speech.tts;
import android.os.ConditionVariable;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
class SilenceMessageParams extends MessageParams {
private final ConditionVariable mCondVar = new ConditionVariable();
private final long mSilenceDurationMs;
- SilenceMessageParams(UtteranceCompletedDispatcher dispatcher,
+ SilenceMessageParams(UtteranceProgressDispatcher dispatcher,
String callingApp, long silenceDurationMs) {
super(dispatcher, callingApp);
mSilenceDurationMs = silenceDurationMs;
diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java
index 779721e..0c0f033 100644
--- a/core/java/android/speech/tts/SynthesisMessageParams.java
+++ b/core/java/android/speech/tts/SynthesisMessageParams.java
@@ -17,7 +17,7 @@
import android.media.AudioFormat;
import android.media.AudioTrack;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
import java.util.LinkedList;
@@ -56,7 +56,7 @@
SynthesisMessageParams(int streamType, int sampleRate,
int audioFormat, int channelCount,
- float volume, float pan, UtteranceCompletedDispatcher dispatcher,
+ float volume, float pan, UtteranceProgressDispatcher dispatcher,
String callingApp, EventLogger logger) {
super(dispatcher, callingApp);
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index fdc2570..38699ea 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -482,7 +482,7 @@
private OnInitListener mInitListener;
// Written from an unspecified application thread, read from
// a binder thread.
- private volatile OnUtteranceCompletedListener mUtteranceCompletedListener;
+ private volatile UtteranceProgressListener mUtteranceProgressListener;
private final Object mStartLock = new Object();
private String mRequestedEngine;
@@ -1146,9 +1146,28 @@
* @param listener The listener to use.
*
* @return {@link #ERROR} or {@link #SUCCESS}.
+ *
+ * @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)}
+ * instead.
*/
+ @Deprecated
public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
- mUtteranceCompletedListener = listener;
+ mUtteranceProgressListener = UtteranceProgressListener.from(listener);
+ return TextToSpeech.SUCCESS;
+ }
+
+ /**
+ * Sets the listener that will be notified of various events related to the
+ * synthesis of a given utterance.
+ *
+ * See {@link UtteranceProgressListener} and
+ * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
+ *
+ * @param listener the listener to use.
+ * @return {@link #ERROR} or {@link #SUCCESS}
+ */
+ public int setOnUtteranceProgressListener(UtteranceProgressListener listener) {
+ mUtteranceProgressListener = listener;
return TextToSpeech.SUCCESS;
}
@@ -1204,10 +1223,26 @@
private ITextToSpeechService mService;
private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
@Override
- public void utteranceCompleted(String utteranceId) {
- OnUtteranceCompletedListener listener = mUtteranceCompletedListener;
+ public void onDone(String utteranceId) {
+ UtteranceProgressListener listener = mUtteranceProgressListener;
if (listener != null) {
- listener.onUtteranceCompleted(utteranceId);
+ listener.onDone(utteranceId);
+ }
+ }
+
+ @Override
+ public void onError(String utteranceId) {
+ UtteranceProgressListener listener = mUtteranceProgressListener;
+ if (listener != null) {
+ listener.onError(utteranceId);
+ }
+ }
+
+ @Override
+ public void onStart(String utteranceId) {
+ UtteranceProgressListener listener = mUtteranceProgressListener;
+ if (listener != null) {
+ listener.onStart(utteranceId);
}
}
};
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 83b6d4c..39922da 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -306,6 +306,7 @@
*/
public int enqueueSpeechItem(int queueMode, final SpeechItem speechItem) {
if (!speechItem.isValid()) {
+ speechItem.dispatchOnError();
return TextToSpeech.ERROR;
}
@@ -332,6 +333,7 @@
return TextToSpeech.SUCCESS;
} else {
Log.w(TAG, "SynthThread has quit");
+ speechItem.dispatchOnError();
return TextToSpeech.ERROR;
}
}
@@ -381,14 +383,16 @@
}
}
- interface UtteranceCompletedDispatcher {
- public void dispatchUtteranceCompleted();
+ interface UtteranceProgressDispatcher {
+ public void dispatchOnDone();
+ public void dispatchOnStart();
+ public void dispatchOnError();
}
/**
* An item in the synth thread queue.
*/
- private abstract class SpeechItem implements UtteranceCompletedDispatcher {
+ private abstract class SpeechItem implements UtteranceProgressDispatcher {
private final String mCallingApp;
protected final Bundle mParams;
private boolean mStarted = false;
@@ -443,10 +447,27 @@
stopImpl();
}
- public void dispatchUtteranceCompleted() {
+ @Override
+ public void dispatchOnDone() {
final String utteranceId = getUtteranceId();
if (!TextUtils.isEmpty(utteranceId)) {
- mCallbacks.dispatchUtteranceCompleted(getCallingApp(), utteranceId);
+ mCallbacks.dispatchOnDone(getCallingApp(), utteranceId);
+ }
+ }
+
+ @Override
+ public void dispatchOnStart() {
+ final String utteranceId = getUtteranceId();
+ if (!TextUtils.isEmpty(utteranceId)) {
+ mCallbacks.dispatchOnStart(getCallingApp(), utteranceId);
+ }
+ }
+
+ @Override
+ public void dispatchOnError() {
+ final String utteranceId = getUtteranceId();
+ if (!TextUtils.isEmpty(utteranceId)) {
+ mCallbacks.dispatchOnError(getCallingApp(), utteranceId);
}
}
@@ -617,9 +638,12 @@
@Override
protected int playImpl() {
+ dispatchOnStart();
int status = super.playImpl();
if (status == TextToSpeech.SUCCESS) {
- dispatchUtteranceCompleted();
+ dispatchOnDone();
+ } else {
+ dispatchOnError();
}
return status;
}
@@ -856,16 +880,34 @@
}
}
- public void dispatchUtteranceCompleted(String packageName, String utteranceId) {
- ITextToSpeechCallback cb;
- synchronized (mAppToCallback) {
- cb = mAppToCallback.get(packageName);
- }
+ public void dispatchOnDone(String packageName, String utteranceId) {
+ ITextToSpeechCallback cb = getCallbackFor(packageName);
if (cb == null) return;
try {
- cb.utteranceCompleted(utteranceId);
+ cb.onDone(utteranceId);
} catch (RemoteException e) {
- Log.e(TAG, "Callback failed: " + e);
+ Log.e(TAG, "Callback onDone failed: " + e);
+ }
+ }
+
+ public void dispatchOnStart(String packageName, String utteranceId) {
+ ITextToSpeechCallback cb = getCallbackFor(packageName);
+ if (cb == null) return;
+ try {
+ cb.onStart(utteranceId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback onStart failed: " + e);
+ }
+
+ }
+
+ public void dispatchOnError(String packageName, String utteranceId) {
+ ITextToSpeechCallback cb = getCallbackFor(packageName);
+ if (cb == null) return;
+ try {
+ cb.onError(utteranceId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback onError failed: " + e);
}
}
@@ -886,6 +928,15 @@
}
}
+ private ITextToSpeechCallback getCallbackFor(String packageName) {
+ ITextToSpeechCallback cb;
+ synchronized (mAppToCallback) {
+ cb = mAppToCallback.get(packageName);
+ }
+
+ return cb;
+ }
+
}
}
diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java
new file mode 100644
index 0000000..a04458a
--- /dev/null
+++ b/core/java/android/speech/tts/UtteranceProgressListener.java
@@ -0,0 +1,68 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package android.speech.tts;
+
+/**
+ * Listener for events relating to the progress of an utterance through
+ * the synthesis queue. Each utterance is associated with a call to
+ * {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} with an
+ * associated utterance identifier, as per {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
+ *
+ * The callbacks specified in this method can be called from multiple threads.
+ */
+public abstract class UtteranceProgressListener {
+ /**
+ * Called when an utterance "starts" as perceived by the caller. This will
+ * be soon before audio is played back in the case of a {@link TextToSpeech#speak}
+ * or before the first bytes of a file are written to storage in the case
+ * of {@link TextToSpeech#synthesizeToFile}.
+ *
+ * @param utteranceId the utterance ID of the utterance.
+ */
+ public abstract void onStart(String utteranceId);
+
+ /**
+ * Called when an utterance has successfully completed processing.
+ * All audio will have been played back by this point for audible output, and all
+ * output will have been written to disk for file synthesis requests.
+ *
+ * This request is guaranteed to be called after {@link #onStart(String)}.
+ *
+ * @param utteranceId the utterance ID of the utterance.
+ */
+ public abstract void onDone(String utteranceId);
+
+ /**
+ * Called when an error has occurred during processing. This can be called
+ * at any point in the synthesis process. Note that there might be calls
+ * to {@link #onStart(String)} for specified utteranceId but there will never
+ * be a call to both {@link #onDone(String)} and {@link #onError(String)} for
+ * the same utterance.
+ *
+ * @param utteranceId the utterance ID of the utterance.
+ */
+ public abstract void onError(String utteranceId);
+
+ /**
+ * Wraps an old deprecated OnUtteranceCompletedListener with a shiny new
+ * progress listener.
+ *
+ * @hide
+ */
+ static UtteranceProgressListener from(
+ final TextToSpeech.OnUtteranceCompletedListener listener) {
+ return new UtteranceProgressListener() {
+ @Override
+ public synchronized void onDone(String utteranceId) {
+ listener.onUtteranceCompleted(utteranceId);
+ }
+
+ // The following methods are left unimplemented.
+ @Override
+ public void onStart(String utteranceId) { }
+
+ @Override
+ public void onError(String utteranceId) { }
+ };
+ }
+}
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index 353b628..22a7528 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -136,12 +136,12 @@
private static java.text.DateFormat sStatusTimeFormat;
private static String sElapsedFormatMMSS;
private static String sElapsedFormatHMMSS;
-
+
private static final String FAST_FORMAT_HMMSS = "%1$d:%2$02d:%3$02d";
private static final String FAST_FORMAT_MMSS = "%1$02d:%2$02d";
private static final char TIME_PADDING = '0';
private static final char TIME_SEPARATOR = ':';
-
+
public static final long SECOND_IN_MILLIS = 1000;
public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
@@ -201,7 +201,7 @@
public static final String YEAR_FORMAT_TWO_DIGITS = "%g";
public static final String WEEKDAY_FORMAT = "%A";
public static final String ABBREV_WEEKDAY_FORMAT = "%a";
-
+
// This table is used to lookup the resource string id of a format string
// used for formatting a start and end date that fall in the same year.
// The index is constructed from a bit-wise OR of the boolean values:
@@ -227,7 +227,7 @@
com.android.internal.R.string.numeric_mdy1_time1_mdy2_time2,
com.android.internal.R.string.numeric_wday1_mdy1_time1_wday2_mdy2_time2,
};
-
+
// This table is used to lookup the resource string id of a format string
// used for formatting a start and end date that fall in the same month.
// The index is constructed from a bit-wise OR of the boolean values:
@@ -256,7 +256,7 @@
/**
* Request the full spelled-out name. For use with the 'abbrev' parameter of
* {@link #getDayOfWeekString} and {@link #getMonthString}.
- *
+ *
* @more <p>
* e.g. "Sunday" or "January"
*/
@@ -265,7 +265,7 @@
/**
* Request an abbreviated version of the name. For use with the 'abbrev'
* parameter of {@link #getDayOfWeekString} and {@link #getMonthString}.
- *
+ *
* @more <p>
* e.g. "Sun" or "Jan"
*/
@@ -347,7 +347,7 @@
* @return Localized month of the year.
*/
public static String getMonthString(int month, int abbrev) {
- // Note that here we use sMonthsMedium for MEDIUM, SHORT and SHORTER.
+ // Note that here we use sMonthsMedium for MEDIUM, SHORT and SHORTER.
// This is a shortcut to not spam the translators with too many variations
// of the same string. If we find that in a language the distinction
// is necessary, we can can add more without changing this API.
@@ -380,7 +380,7 @@
* @hide Pending API council approval
*/
public static String getStandaloneMonthString(int month, int abbrev) {
- // Note that here we use sMonthsMedium for MEDIUM, SHORT and SHORTER.
+ // Note that here we use sMonthsMedium for MEDIUM, SHORT and SHORTER.
// This is a shortcut to not spam the translators with too many variations
// of the same string. If we find that in a language the distinction
// is necessary, we can can add more without changing this API.
@@ -434,7 +434,7 @@
* <p>
* Can use {@link #FORMAT_ABBREV_RELATIVE} flag to use abbreviated relative
* times, like "42 mins ago".
- *
+ *
* @param time the time to describe, in milliseconds
* @param now the current time in milliseconds
* @param minResolution the minimum timespan to report. For example, a time
@@ -450,7 +450,7 @@
int flags) {
Resources r = Resources.getSystem();
boolean abbrevRelative = (flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0;
-
+
boolean past = (now >= time);
long duration = Math.abs(now - time);
@@ -525,7 +525,7 @@
String format = r.getQuantityString(resId, (int) count);
return String.format(format, count);
}
-
+
/**
* Returns the number of days passed between two dates.
*
@@ -555,7 +555,7 @@
* <li>Dec 12, 4:12 AM</li>
* <li>11/14/2007, 8:20 AM</li>
* </ul>
- *
+ *
* @param time some time in the past.
* @param minResolution the minimum elapsed time (in milliseconds) to report
* when showing relative times. For example, a time 3 seconds in
@@ -584,7 +584,7 @@
}
CharSequence timeClause = formatDateRange(c, time, time, FORMAT_SHOW_TIME);
-
+
String result;
if (duration < transitionResolution) {
CharSequence relativeClause = getRelativeTimeSpanString(time, now, minResolution, flags);
@@ -601,7 +601,7 @@
* Returns a string describing a day relative to the current day. For example if the day is
* today this function returns "Today", if the day was a week ago it returns "7 days ago", and
* if the day is in 2 weeks it returns "in 14 days".
- *
+ *
* @param r the resources to get the strings from
* @param day the relative day to describe in UTC milliseconds
* @param today the current time in UTC milliseconds
@@ -618,7 +618,7 @@
int days = Math.abs(currentDay - startDay);
boolean past = (today > day);
-
+
if (days == 1) {
if (past) {
return r.getString(com.android.internal.R.string.yesterday);
@@ -635,7 +635,7 @@
} else {
resId = com.android.internal.R.plurals.in_num_days;
}
-
+
String format = r.getQuantityString(resId, days);
return String.format(format, days);
}
@@ -677,11 +677,11 @@
public static String formatElapsedTime(long elapsedSeconds) {
return formatElapsedTime(null, elapsedSeconds);
}
-
+
/**
* Formats an elapsed time in the form "MM:SS" or "H:MM:SS"
* for display on the call-in-progress screen.
- *
+ *
* @param recycle {@link StringBuilder} to recycle, if possible
* @param elapsedSeconds the elapsed time in seconds.
*/
@@ -724,7 +724,7 @@
}
sb.append(hours);
sb.append(TIME_SEPARATOR);
- if (minutes < 10) {
+ if (minutes < 10) {
sb.append(TIME_PADDING);
} else {
sb.append(toDigitChar(minutes / 10));
@@ -755,7 +755,7 @@
} else {
sb.setLength(0);
}
- if (minutes < 10) {
+ if (minutes < 10) {
sb.append(TIME_PADDING);
} else {
sb.append(toDigitChar(minutes / 10));
@@ -777,11 +777,11 @@
private static char toDigitChar(long digit) {
return (char) (digit + '0');
}
-
+
/**
* Format a date / time such that if the then is on the same day as now, it shows
* just the time and if it's a different day, it shows just the date.
- *
+ *
* <p>The parameters dateFormat and timeFormat should each be one of
* {@link java.text.DateFormat#DEFAULT},
* {@link java.text.DateFormat#FULL},
@@ -833,14 +833,14 @@
public static boolean isToday(long when) {
Time time = new Time();
time.set(when);
-
+
int thenYear = time.year;
int thenMonth = time.month;
int thenMonthDay = time.monthDay;
time.set(System.currentTimeMillis());
return (thenYear == time.year)
- && (thenMonth == time.month)
+ && (thenMonth == time.month)
&& (thenMonthDay == time.monthDay);
}
@@ -914,7 +914,7 @@
public static String writeDateTime(Calendar cal, StringBuilder sb)
{
int n;
-
+
n = cal.get(Calendar.YEAR);
sb.setCharAt(3, (char)('0'+n%10));
n /= 10;
@@ -1015,7 +1015,7 @@
/**
* Formats a date or a time range according to the local conventions.
- *
+ *
* <p>
* Example output strings (date formats in these examples are shown using
* the US date format convention but that may change depending on the
@@ -1036,10 +1036,10 @@
* <li>Oct 9, 8:00am - Oct 10, 5:00pm</li>
* <li>12/31/2007 - 01/01/2008</li>
* </ul>
- *
+ *
* <p>
* The flags argument is a bitmask of options from the following list:
- *
+ *
* <ul>
* <li>FORMAT_SHOW_TIME</li>
* <li>FORMAT_SHOW_WEEKDAY</li>
@@ -1061,15 +1061,15 @@
* <li>FORMAT_ABBREV_ALL</li>
* <li>FORMAT_NUMERIC_DATE</li>
* </ul>
- *
+ *
* <p>
* If FORMAT_SHOW_TIME is set, the time is shown as part of the date range.
* If the start and end time are the same, then just the start time is
* shown.
- *
+ *
* <p>
* If FORMAT_SHOW_WEEKDAY is set, then the weekday is shown.
- *
+ *
* <p>
* If FORMAT_SHOW_YEAR is set, then the year is always shown.
* If FORMAT_NO_YEAR is set, then the year is not shown.
@@ -1082,80 +1082,91 @@
* Normally the date is shown unless the start and end day are the same.
* If FORMAT_SHOW_DATE is set, then the date is always shown, even for
* same day ranges.
- *
+ *
* <p>
* If FORMAT_NO_MONTH_DAY is set, then if the date is shown, just the
* month name will be shown, not the day of the month. For example,
* "January, 2008" instead of "January 6 - 12, 2008".
- *
+ *
* <p>
* If FORMAT_CAP_AMPM is set and 12-hour time is used, then the "AM"
* and "PM" are capitalized. You should not use this flag
* because in some locales these terms cannot be capitalized, and in
* many others it doesn't make sense to do so even though it is possible.
- *
+ *
* <p>
* If FORMAT_NO_NOON is set and 12-hour time is used, then "12pm" is
* shown instead of "noon".
- *
+ *
* <p>
* If FORMAT_CAP_NOON is set and 12-hour time is used, then "Noon" is
* shown instead of "noon". You should probably not use this flag
* because in many locales it will not make sense to capitalize
* the term.
- *
+ *
* <p>
* If FORMAT_NO_MIDNIGHT is set and 12-hour time is used, then "12am" is
* shown instead of "midnight".
- *
+ *
* <p>
* If FORMAT_CAP_MIDNIGHT is set and 12-hour time is used, then "Midnight"
* is shown instead of "midnight". You should probably not use this
* flag because in many locales it will not make sense to capitalize
* the term.
- *
+ *
* <p>
* If FORMAT_12HOUR is set and the time is shown, then the time is
* shown in the 12-hour time format. You should not normally set this.
* Instead, let the time format be chosen automatically according to the
* system settings. If both FORMAT_12HOUR and FORMAT_24HOUR are set, then
* FORMAT_24HOUR takes precedence.
- *
+ *
* <p>
* If FORMAT_24HOUR is set and the time is shown, then the time is
* shown in the 24-hour time format. You should not normally set this.
* Instead, let the time format be chosen automatically according to the
* system settings. If both FORMAT_12HOUR and FORMAT_24HOUR are set, then
* FORMAT_24HOUR takes precedence.
- *
+ *
* <p>
* If FORMAT_UTC is set, then the UTC time zone is used for the start
* and end milliseconds unless a time zone is specified. If a time zone
* is specified it will be used regardless of the FORMAT_UTC flag.
- *
+ *
* <p>
* If FORMAT_ABBREV_TIME is set and 12-hour time format is used, then the
* start and end times (if shown) are abbreviated by not showing the minutes
* if they are zero. For example, instead of "3:00pm" the time would be
* abbreviated to "3pm".
- *
+ *
* <p>
* If FORMAT_ABBREV_WEEKDAY is set, then the weekday (if shown) is
* abbreviated to a 3-letter string.
- *
+ *
* <p>
* If FORMAT_ABBREV_MONTH is set, then the month (if shown) is abbreviated
* to a 3-letter string.
- *
+ *
* <p>
* If FORMAT_ABBREV_ALL is set, then the weekday and the month (if shown)
* are abbreviated to 3-letter strings.
- *
+ *
* <p>
* If FORMAT_NUMERIC_DATE is set, then the date is shown in numeric format
* instead of using the name of the month. For example, "12/31/2008"
* instead of "December 31, 2008".
- *
+ *
+ * <p>
+ * If the end date ends at 12:00am at the beginning of a day, it is
+ * formatted as the end of the previous day in two scenarios:
+ * <ul>
+ * <li>For single day events. This results in "8pm - midnight" instead of
+ * "Nov 10, 8pm - Nov 11, 12am".</li>
+ * <li>When the time is not displayed. This results in "Nov 10 - 11" for
+ * an event with a start date of Nov 10 and an end date of Nov 12 at
+ * 00:00.</li>
+ * </ul>
+ *
* @param context the context is required only if the time is shown
* @param formatter the Formatter used for formatting the date range.
* Note: be sure to call setLength(0) on StringBuilder passed to
@@ -1165,7 +1176,7 @@
* @param flags a bit mask of options
* @param timeZone the time zone to compute the string in. Use null for local
* or if the FORMAT_UTC flag is being used.
- *
+ *
* @return the formatter with the formatted date/time range appended to the string buffer.
*/
public static Formatter formatDateRange(Context context, Formatter formatter, long startMillis,
@@ -1215,20 +1226,6 @@
dayDistance = endJulianDay - startJulianDay;
}
- // If the end date ends at 12am at the beginning of a day,
- // then modify it to make it look like it ends at midnight on
- // the previous day. This will allow us to display "8pm - midnight",
- // for example, instead of "Nov 10, 8pm - Nov 11, 12am". But we only do
- // this if it is midnight of the same day as the start date because
- // for multiple-day events, an end time of "midnight on Nov 11" is
- // ambiguous and confusing (is that midnight the start of Nov 11, or
- // the end of Nov 11?).
- // If we are not showing the time then also adjust the end date
- // for multiple-day events. This is to allow us to display, for
- // example, "Nov 10 -11" for an event with a start date of Nov 10
- // and an end date of Nov 12 at 00:00.
- // If the start and end time are the same, then skip this and don't
- // adjust the date.
if (!isInstant
&& (endDate.hour | endDate.minute | endDate.second) == 0
&& (!showTime || dayDistance <= 1)) {
@@ -1592,7 +1589,7 @@
* <li>Wed, October 31</li>
* <li>10/31/2007</li>
* </ul>
- *
+ *
* @param context the context is required only if the time is shown
* @param millis a point in time in UTC milliseconds
* @param flags a bit mask of formatting options
@@ -1607,13 +1604,13 @@
* are counted starting at midnight, which means that assuming that the current
* time is March 31st, 0:30:
* <ul>
- * <li>"millis=0:10 today" will be displayed as "0:10"</li>
+ * <li>"millis=0:10 today" will be displayed as "0:10"</li>
* <li>"millis=11:30pm the day before" will be displayed as "Mar 30"</li>
* </ul>
* If the given millis is in a different year, then the full date is
* returned in numeric format (e.g., "10/12/2008").
- *
- * @param withPreposition If true, the string returned will include the correct
+ *
+ * @param withPreposition If true, the string returned will include the correct
* preposition ("at 9:20am", "on 10/12/2008" or "on May 29").
*/
public static CharSequence getRelativeTimeSpanString(Context c, long millis,
@@ -1661,9 +1658,9 @@
}
return result;
}
-
+
/**
- * Convenience function to return relative time string without preposition.
+ * Convenience function to return relative time string without preposition.
* @param c context for resources
* @param millis time in milliseconds
* @return {@link CharSequence} containing relative time.
@@ -1672,7 +1669,7 @@
public static CharSequence getRelativeTimeSpanString(Context c, long millis) {
return getRelativeTimeSpanString(c, millis, false /* no preposition */);
}
-
+
private static Time sNowTime;
private static Time sThenTime;
}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 9a39345..67d9033 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -315,6 +315,27 @@
private static native void nFlushCaches(int level);
+ /**
+ * Release all resources associated with the underlying caches. This should
+ * only be called after a full flushCaches().
+ *
+ * @hide
+ */
+ public static void terminateCaches() {
+ nTerminateCaches();
+ }
+
+ private static native void nTerminateCaches();
+
+ /**
+ * @hide
+ */
+ public static void initCaches() {
+ nInitCaches();
+ }
+
+ private static native void nInitCaches();
+
///////////////////////////////////////////////////////////////////////////
// Display list
///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index c2ac79d..e0167d8 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -25,6 +25,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.Log;
+import com.google.android.gles_jni.EGLImpl;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
@@ -344,6 +345,15 @@
}
/**
+ * Invoke this method when the system needs to clean up all resources
+ * associated with hardware rendering.
+ */
+ static void terminate() {
+ Log.d(LOG_TAG, "Terminating hardware rendering");
+ Gl20Renderer.terminate();
+ }
+
+ /**
* Indicates whether hardware acceleration is currently enabled.
*
* @return True if hardware acceleration is in use, false otherwise.
@@ -651,6 +661,8 @@
throw new Surface.OutOfResourcesException("eglMakeCurrent failed "
+ GLUtils.getEGLErrorString(sEgl.eglGetError()));
}
+
+ initCaches();
// If mDirtyRegions is set, this means we have an EGL configuration
// with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
@@ -671,6 +683,8 @@
return mEglContext.getGL();
}
+ abstract void initCaches();
+
EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
int[] attribs = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
@@ -914,6 +928,11 @@
EGL_NONE
};
}
+
+ @Override
+ void initCaches() {
+ GLES20Canvas.initCaches();
+ }
@Override
boolean canDraw() {
@@ -1006,16 +1025,7 @@
if (eglContext == null) {
return;
} else {
- synchronized (sPbufferLock) {
- // Create a temporary 1x1 pbuffer so we have a context
- // to clear our OpenGL objects
- if (sPbuffer == null) {
- sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
- EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
- });
- }
- }
- sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
+ usePbufferSurface(eglContext);
}
switch (level) {
@@ -1029,5 +1039,46 @@
break;
}
}
+
+ private static void usePbufferSurface(EGLContext eglContext) {
+ synchronized (sPbufferLock) {
+ // Create a temporary 1x1 pbuffer so we have a context
+ // to clear our OpenGL objects
+ if (sPbuffer == null) {
+ sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
+ EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
+ });
+ }
+ }
+ sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
+ }
+
+ static void terminate() {
+ synchronized (sEglLock) {
+ if (sEgl == null) return;
+
+ if (EGLImpl.getInitCount(sEglDisplay) == 1) {
+ EGLContext eglContext = sEglContextStorage.get();
+ if (eglContext == null) return;
+
+ usePbufferSurface(eglContext);
+ GLES20Canvas.terminateCaches();
+
+ sEgl.eglDestroyContext(sEglDisplay, eglContext);
+ sEglContextStorage.remove();
+
+ sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ sEgl.eglReleaseThread();
+ sEgl.eglTerminate(sEglDisplay);
+
+ sEgl = null;
+ sEglDisplay = null;
+ sEglConfig = null;
+ sPbuffer = null;
+ }
+ }
+ }
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ec25b64..723846a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -568,7 +568,7 @@
}
}
- private void destroyHardwareResources() {
+ void destroyHardwareResources() {
if (mAttachInfo.mHardwareRenderer != null) {
if (mAttachInfo.mHardwareRenderer.isEnabled()) {
mAttachInfo.mHardwareRenderer.destroyLayers(mView);
@@ -881,12 +881,10 @@
|| mNewSurfaceNeeded;
WindowManager.LayoutParams params = null;
- int windowAttributesChanges = 0;
if (mWindowAttributesChanged) {
mWindowAttributesChanged = false;
surfaceChanged = true;
params = lp;
- windowAttributesChanges = mWindowAttributesChangesFlag;
}
CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 5ef4f3e..d89bc36 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -16,6 +16,8 @@
package android.view;
+import android.app.ActivityManager;
+import android.content.ComponentCallbacks2;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
@@ -409,7 +411,30 @@
*/
public void trimMemory(int level) {
if (HardwareRenderer.isAvailable()) {
- HardwareRenderer.trimMemory(level);
+ switch (level) {
+ case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
+ case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
+ // On low and medium end gfx devices
+ if (!ActivityManager.isHighEndGfx(getDefaultDisplay())) {
+ // Force a full memory flush
+ HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
+ // Destroy all hardware surfaces and resources associated to
+ // known windows
+ synchronized (this) {
+ if (mViews == null) return;
+ int count = mViews.length;
+ for (int i = 0; i < count; i++) {
+ mRoots[i].destroyHardwareResources();
+ }
+ }
+ // Terminate the hardware renderer to free all resources
+ HardwareRenderer.terminate();
+ break;
+ }
+ // high end gfx devices fall through to next case
+ default:
+ HardwareRenderer.trimMemory(level);
+ }
}
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index b020cbc..596cd10 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2861,8 +2861,8 @@
}
// Used to avoid sending many visible rect messages.
- private Rect mLastVisibleRectSent;
- private Rect mLastGlobalRect;
+ private Rect mLastVisibleRectSent = new Rect();
+ private Rect mLastGlobalRect = new Rect();
private Rect mVisibleRect = new Rect();
private Rect mGlobalVisibleRect = new Rect();
private Point mScrollOffset = new Point();
@@ -2878,7 +2878,7 @@
mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
nativeMoveGeneration(), mSendScrollEvent ? 1 : 0, mScrollOffset);
}
- mLastVisibleRectSent = mVisibleRect;
+ mLastVisibleRectSent.set(mVisibleRect);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
}
if (getGlobalVisibleRect(mGlobalVisibleRect)
@@ -2894,7 +2894,7 @@
if (!mBlockWebkitViewMessages) {
mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, mGlobalVisibleRect);
}
- mLastGlobalRect = mGlobalVisibleRect;
+ mLastGlobalRect.set(mGlobalVisibleRect);
}
return mVisibleRect;
}
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index fd2abc2..326587e 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -129,7 +129,7 @@
mEdge = res.getDrawable(R.drawable.overscroll_edge);
mGlow = res.getDrawable(R.drawable.overscroll_glow);
- mMinWidth = (int) (context.getResources().getDisplayMetrics().density * MIN_WIDTH + 0.5f);
+ mMinWidth = (int) (res.getDisplayMetrics().density * MIN_WIDTH + 0.5f);
mInterpolator = new DecelerateInterpolator();
}
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index c1e36ed..73e1273 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -1036,6 +1036,7 @@
}
}
+ @RemotableViewMethod
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 8ba7bee..5fa4ad0 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1248,6 +1248,8 @@
*/
public void dismiss() {
if (isShowing() && mPopupView != null) {
+ mIsShowing = false;
+
unregisterForScrollChanged();
try {
@@ -1257,7 +1259,6 @@
((ViewGroup) mPopupView).removeView(mContentView);
}
mPopupView = null;
- mIsShowing = false;
if (mOnDismissListener != null) {
mOnDismissListener.onDismiss();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6638ea6..0dd55bf 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
+import android.content.res.CompatibilityInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -449,18 +450,19 @@
super(context, attrs, defStyle);
mText = "";
+ final Resources res = getResources();
+ final CompatibilityInfo compat = res.getCompatibilityInfo();
+
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
- mTextPaint.density = getResources().getDisplayMetrics().density;
- mTextPaint.setCompatibilityScaling(
- getResources().getCompatibilityInfo().applicationScale);
+ mTextPaint.density = res.getDisplayMetrics().density;
+ mTextPaint.setCompatibilityScaling(compat.applicationScale);
// If we get the paint from the skin, we should set it to left, since
// the layout always wants it to be left.
// mTextPaint.setTextAlign(Paint.Align.LEFT);
mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mHighlightPaint.setCompatibilityScaling(
- getResources().getCompatibilityInfo().applicationScale);
+ mHighlightPaint.setCompatibilityScaling(compat.applicationScale);
mMovement = getDefaultMovementMethod();
mTransformation = null;
@@ -6097,18 +6099,13 @@
int physicalWidth = width;
if (mHorizontallyScrolling) {
- width = getTextWidth();
+ width = VERY_WIDE;
}
makeNewLayout(width, physicalWidth, UNKNOWN_BORING, UNKNOWN_BORING,
physicalWidth, false);
}
- private int getTextWidth() {
- final int length = mText.length();
- return (length == 0) ? 0 : (int) (getPaint().measureText(mText, 0, length) + 0.5f);
- }
-
@Override
protected void resetResolvedLayoutDirection() {
super.resetResolvedLayoutDirection();
@@ -6554,7 +6551,7 @@
int want = width - getCompoundPaddingLeft() - getCompoundPaddingRight();
int unpaddedWidth = want;
- if (mHorizontallyScrolling) want = getTextWidth();
+ if (mHorizontallyScrolling) want = VERY_WIDE;
int hintWant = want;
int hintWidth = (mHintLayout == null) ? hintWant : mHintLayout.getWidth();
@@ -11544,6 +11541,9 @@
private boolean mHighlightPathBogus = true;
private static final RectF sTempRect = new RectF();
+ // XXX should be much larger
+ private static final int VERY_WIDE = 1024*1024;
+
private static final int BLINK = 500;
private static final int ANIMATED_SCROLL_GAP = 250;
diff --git a/core/jni/android_nfc_NdefRecord.cpp b/core/jni/android_nfc_NdefRecord.cpp
index e8cc4c6..67907b6 100644
--- a/core/jni/android_nfc_NdefRecord.cpp
+++ b/core/jni/android_nfc_NdefRecord.cpp
@@ -149,7 +149,7 @@
/* Set flags field */
mFlags = e->GetFieldID(record_cls, "mFlags", "B");
- e->SetIntField(o, mFlags, record.Flags);
+ e->SetByteField(o, mFlags, record.Flags);
ret = 0;
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index e79de2d..4f75fad 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -134,6 +134,18 @@
}
}
+static void android_view_GLES20Canvas_initCaches(JNIEnv* env, jobject clazz) {
+ if (Caches::hasInstance()) {
+ Caches::getInstance().init();
+ }
+}
+
+static void android_view_GLES20Canvas_terminateCaches(JNIEnv* env, jobject clazz) {
+ if (Caches::hasInstance()) {
+ Caches::getInstance().terminate();
+ }
+}
+
// ----------------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------------
@@ -756,6 +768,8 @@
{ "nPreserveBackBuffer", "()Z", (void*) android_view_GLES20Canvas_preserveBackBuffer },
{ "nDisableVsync", "()V", (void*) android_view_GLES20Canvas_disableVsync },
{ "nFlushCaches", "(I)V", (void*) android_view_GLES20Canvas_flushCaches },
+ { "nInitCaches", "()V", (void*) android_view_GLES20Canvas_initCaches },
+ { "nTerminateCaches", "()V", (void*) android_view_GLES20Canvas_terminateCaches },
{ "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer },
{ "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer },
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 02974f9a..4fe7600 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -24,6 +24,8 @@
#include <EGL/egl.h>
#include <GLES/gl.h>
+#include <EGL/egl_display.h>
+
#include <surfaceflinger/Surface.h>
#include <SkBitmap.h>
#include <SkPixelRef.h>
@@ -173,6 +175,16 @@
return success;
}
+static jint jni_getInitCount(JNIEnv *_env, jobject _clazz, jobject display) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ egl_display_t* eglDisplay = get_display(dpy);
+ return eglDisplay ? eglDisplay->getRefsCount() : 0;
+}
+
+static jboolean jni_eglReleaseThread(JNIEnv *_env, jobject _this) {
+ return eglReleaseThread();
+}
+
static jboolean jni_eglChooseConfig(JNIEnv *_env, jobject _this, jobject display,
jintArray attrib_list, jobjectArray configs, jint config_size, jintArray num_config) {
if (display == NULL
@@ -526,6 +538,8 @@
{"eglInitialize", "(" DISPLAY "[I)Z", (void*)jni_eglInitialize },
{"eglQueryContext", "(" DISPLAY CONTEXT "I[I)Z", (void*)jni_eglQueryContext },
{"eglQuerySurface", "(" DISPLAY SURFACE "I[I)Z", (void*)jni_eglQuerySurface },
+{"eglReleaseThread","()Z", (void*)jni_eglReleaseThread },
+{"getInitCount", "(" DISPLAY ")I", (void*)jni_getInitCount },
{"eglChooseConfig", "(" DISPLAY "[I[" CONFIG "I[I)Z", (void*)jni_eglChooseConfig },
{"_eglCreateContext","(" DISPLAY CONFIG CONTEXT "[I)I", (void*)jni_eglCreateContext },
{"eglGetConfigs", "(" DISPLAY "[" CONFIG "I[I)Z", (void*)jni_eglGetConfigs },
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 79acd55..380b3d8 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -604,10 +604,13 @@
}
Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true);
if (config == Config.ARGB_8888 && !hasAlpha) {
- bm.eraseColor(0xff000000);
+ nativeErase(bm.mNativeBitmap, 0xff000000);
nativeSetHasAlpha(bm.mNativeBitmap, hasAlpha);
} else {
- bm.eraseColor(0);
+ // No need to initialize it to zeroes; it is backed by a VM byte array
+ // which is by definition preinitialized to all zeroes.
+ //
+ //nativeErase(bm.mNativeBitmap, 0);
}
return bm;
}
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 9aa6700..534afce 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -54,6 +54,7 @@
METADATA_KEY_BITRATE = 20,
METADATA_KEY_TIMED_TEXT_LANGUAGES = 21,
METADATA_KEY_IS_DRM = 22,
+ METADATA_KEY_LOCATION = 23,
// Add more here...
};
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 57f678c..4cdee17 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -85,6 +85,7 @@
kKeyDate = 'date', // cstring
kKeyWriter = 'writ', // cstring
kKeyCompilation = 'cpil', // cstring
+ kKeyLocation = 'loc ', // cstring
kKeyTimeScale = 'tmsl', // int32_t
// video profile and level
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 75b07de..f293cba 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -46,22 +46,16 @@
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO),
- lastDstMode(GL_ZERO), currentProgram(NULL) {
+Caches::Caches(): Singleton<Caches>(), mInitialized(false) {
GLint maxTextureUnits;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
}
- glGenBuffers(1, &meshBuffer);
- glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
- glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
-
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
- mCurrentBuffer = meshBuffer;
- mRegionMesh = NULL;
+ init();
mDebugLevel = readDebugLevel();
LOGD("Enabling debug mode %d", mDebugLevel);
@@ -71,8 +65,40 @@
#endif
}
-Caches::~Caches() {
+void Caches::init() {
+ if (mInitialized) return;
+
+ glGenBuffers(1, &meshBuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
+
+ mCurrentBuffer = meshBuffer;
+ mRegionMesh = NULL;
+
+ blend = false;
+ lastSrcMode = GL_ZERO;
+ lastDstMode = GL_ZERO;
+ currentProgram = NULL;
+
+ mInitialized = true;
+}
+
+void Caches::terminate() {
+ if (!mInitialized) return;
+
+ glDeleteBuffers(1, &meshBuffer);
+ mCurrentBuffer = 0;
+
+ glDeleteBuffers(1, &mRegionMeshIndices);
delete[] mRegionMesh;
+ mRegionMesh = NULL;
+
+ fboCache.clear();
+
+ programCache.clear();
+ currentProgram = NULL;
+
+ mInitialized = false;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 9b0d7c6..5e58a9e 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -86,7 +86,6 @@
class ANDROID_API Caches: public Singleton<Caches> {
Caches();
- ~Caches();
friend class Singleton<Caches>;
@@ -109,6 +108,11 @@
};
/**
+ * Initializes the cache.
+ */
+ void init();
+
+ /**
* Flush the cache.
*
* @param mode Indicates how much of the cache should be flushed
@@ -116,6 +120,12 @@
void flush(FlushMode mode);
/**
+ * Destroys all resources associated with this cache. This should
+ * be called after a flush(kFlushMode_Full).
+ */
+ void terminate();
+
+ /**
* Indicates whether the renderer is in debug mode.
* This debug mode provides limited information to app developers.
*/
@@ -194,6 +204,7 @@
private:
DebugLevel mDebugLevel;
+ bool mInitialized;
}; // class Caches
}; // namespace uirenderer
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 10694c3..11ecd1f 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -458,5 +458,12 @@
* @hide
*/
public static final int METADATA_KEY_IS_DRM = 22;
+ /**
+ * This key retrieves the location information, if available.
+ * The location should be specified according to ISO-6709 standard, under
+ * a mp4/3gp box "@xyz". Location with longitude of -90 degrees and latitude
+ * of 180 degrees will be retrieved as "-90.0000+180.0000", for instance.
+ */
+ public static final int METADATA_KEY_LOCATION = 23;
// Add more here...
}
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 6db87fe..e9b8042 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -47,17 +47,22 @@
VISUALIZER_STATE_ACTIVE,
};
+// maximum number of reads from same buffer before resetting capture buffer. This means
+// that the framework has stopped playing audio and we must start returning silence
+#define MAX_STALL_COUNT 10
+
struct VisualizerContext {
const struct effect_interface_s *mItfe;
effect_config_t mConfig;
- uint32_t mState;
uint32_t mCaptureIdx;
uint32_t mCaptureSize;
- uint32_t mCurrentBuf;
+ uint8_t mState;
+ uint8_t mCurrentBuf;
+ uint8_t mLastBuf;
+ uint8_t mStallCount;
uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
};
-
//
//--- Local functions
//
@@ -66,6 +71,8 @@
{
pContext->mCaptureIdx = 0;
pContext->mCurrentBuf = 0;
+ pContext->mLastBuf = 1;
+ pContext->mStallCount = 0;
memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
}
@@ -417,9 +424,24 @@
memcpy(pReplyData,
pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
pContext->mCaptureSize);
+ // if audio framework has stopped playing audio although the effect is still
+ // active we must clear the capture buffer to return silence
+ if (pContext->mLastBuf == pContext->mCurrentBuf) {
+ if (pContext->mStallCount < MAX_STALL_COUNT) {
+ if (++pContext->mStallCount == MAX_STALL_COUNT) {
+ memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
+ 0x80,
+ pContext->mCaptureSize);
+ }
+ }
+ } else {
+ pContext->mStallCount = 0;
+ }
+ pContext->mLastBuf = pContext->mCurrentBuf;
} else {
memset(pReplyData, 0x80, pContext->mCaptureSize);
}
+
break;
default:
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 1b286fa..7b6fa38 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1136,6 +1136,41 @@
break;
}
+ // @xyz
+ case FOURCC('\xA9', 'x', 'y', 'z'):
+ {
+ // Best case the total data length inside "@xyz" box
+ // would be 8, for instance "@xyz" + "\x00\x04\x15\xc7" + "0+0/",
+ // where "\x00\x04" is the text string length with value = 4,
+ // "\0x15\xc7" is the language code = en, and "0+0" is a
+ // location (string) value with longitude = 0 and latitude = 0.
+ if (chunk_data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ // Worst case the location string length would be 18,
+ // for instance +90.0000-180.0000, without the trailing "/" and
+ // the string length + language code.
+ char buffer[18];
+
+ // Substracting 5 from the data size is because the text string length +
+ // language code takes 4 bytes, and the trailing slash "/" takes 1 byte.
+ off64_t location_length = chunk_data_size - 5;
+ if (location_length >= (off64_t) sizeof(buffer)) {
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->readAt(
+ data_offset + 4, buffer, location_length) < location_length) {
+ return ERROR_IO;
+ }
+
+ buffer[location_length] = '\0';
+ mFileMetaData->setCString(kKeyLocation, buffer);
+ *offset += chunk_size;
+ break;
+ }
+
case FOURCC('e', 's', 'd', 's'):
{
if (chunk_data_size < 4) {
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 022b169..2634da0 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -418,6 +418,7 @@
{ kKeyYear, METADATA_KEY_YEAR },
{ kKeyWriter, METADATA_KEY_WRITER },
{ kKeyCompilation, METADATA_KEY_COMPILATION },
+ { kKeyLocation, METADATA_KEY_LOCATION },
};
static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index c450158..0fbbb9e 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -187,10 +187,13 @@
return true;
}
-static void MakeSocketBlocking(int s, bool blocking) {
+static status_t MakeSocketBlocking(int s, bool blocking) {
// Make socket non-blocking.
int flags = fcntl(s, F_GETFL, 0);
- CHECK_NE(flags, -1);
+
+ if (flags == -1) {
+ return UNKNOWN_ERROR;
+ }
if (blocking) {
flags &= ~O_NONBLOCK;
@@ -198,7 +201,9 @@
flags |= O_NONBLOCK;
}
- CHECK_NE(fcntl(s, F_SETFL, flags), -1);
+ flags = fcntl(s, F_SETFL, flags);
+
+ return flags == -1 ? UNKNOWN_ERROR : OK;
}
void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
@@ -302,27 +307,32 @@
reply->post();
}
+void ARTSPConnection::performDisconnect() {
+ if (mUIDValid) {
+ HTTPBase::UnRegisterSocketUserTag(mSocket);
+ }
+ close(mSocket);
+ mSocket = -1;
+
+ flushPendingRequests();
+
+ mUser.clear();
+ mPass.clear();
+ mAuthType = NONE;
+ mNonce.clear();
+
+ mState = DISCONNECTED;
+}
+
void ARTSPConnection::onDisconnect(const sp<AMessage> &msg) {
if (mState == CONNECTED || mState == CONNECTING) {
- if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- }
- close(mSocket);
- mSocket = -1;
-
- flushPendingRequests();
+ performDisconnect();
}
sp<AMessage> reply;
CHECK(msg->findMessage("reply", &reply));
reply->setInt32("result", OK);
- mState = DISCONNECTED;
-
- mUser.clear();
- mPass.clear();
- mAuthType = NONE;
- mNonce.clear();
reply->post();
}
@@ -427,21 +437,25 @@
send(mSocket, request.c_str() + numBytesSent,
request.size() - numBytesSent, 0);
- if (n == 0) {
- // Server closed the connection.
- LOGE("Server unexpectedly closed the connection.");
+ if (n < 0 && errno == EINTR) {
+ continue;
+ }
- reply->setInt32("result", ERROR_IO);
- reply->post();
- return;
- } else if (n < 0) {
- if (errno == EINTR) {
- continue;
+ if (n <= 0) {
+ performDisconnect();
+
+ if (n == 0) {
+ // Server closed the connection.
+ LOGE("Server unexpectedly closed the connection.");
+
+ reply->setInt32("result", ERROR_IO);
+ reply->post();
+ } else {
+ LOGE("Error sending rtsp request. (%s)", strerror(errno));
+ reply->setInt32("result", -errno);
+ reply->post();
}
- LOGE("Error sending rtsp request.");
- reply->setInt32("result", -errno);
- reply->post();
return;
}
@@ -512,17 +526,22 @@
size_t offset = 0;
while (offset < size) {
ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0);
- if (n == 0) {
- // Server closed the connection.
- LOGE("Server unexpectedly closed the connection.");
- return ERROR_IO;
- } else if (n < 0) {
- if (errno == EINTR) {
- continue;
- }
- LOGE("Error reading rtsp response.");
- return -errno;
+ if (n < 0 && errno == EINTR) {
+ continue;
+ }
+
+ if (n <= 0) {
+ performDisconnect();
+
+ if (n == 0) {
+ // Server closed the connection.
+ LOGE("Server unexpectedly closed the connection.");
+ return ERROR_IO;
+ } else {
+ LOGE("Error reading rtsp response. (%s)", strerror(errno));
+ return -errno;
+ }
}
offset += (size_t)n;
@@ -681,24 +700,8 @@
if (contentLength > 0) {
response->mContent = new ABuffer(contentLength);
- size_t numBytesRead = 0;
- while (numBytesRead < contentLength) {
- ssize_t n = recv(
- mSocket, response->mContent->data() + numBytesRead,
- contentLength - numBytesRead, 0);
-
- if (n == 0) {
- // Server closed the connection.
- TRESPASS();
- } else if (n < 0) {
- if (errno == EINTR) {
- continue;
- }
-
- TRESPASS();
- }
-
- numBytesRead += (size_t)n;
+ if (receive(response->mContent->data(), contentLength) != OK) {
+ return false;
}
}
@@ -765,17 +768,20 @@
send(mSocket, response.c_str() + numBytesSent,
response.size() - numBytesSent, 0);
- if (n == 0) {
- // Server closed the connection.
- LOGE("Server unexpectedly closed the connection.");
+ if (n < 0 && errno == EINTR) {
+ continue;
+ }
- return false;
- } else if (n < 0) {
- if (errno == EINTR) {
- continue;
+ if (n <= 0) {
+ if (n == 0) {
+ // Server closed the connection.
+ LOGE("Server unexpectedly closed the connection.");
+ } else {
+ LOGE("Error sending rtsp response (%s).", strerror(errno));
}
- LOGE("Error sending rtsp response.");
+ performDisconnect();
+
return false;
}
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 5cb84fd..68f2d59 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -91,6 +91,8 @@
AString mUserAgent;
+ void performDisconnect();
+
void onConnect(const sp<AMessage> &msg);
void onDisconnect(const sp<AMessage> &msg);
void onCompleteConnection(const sp<AMessage> &msg);
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 3789b8d..dd049c2 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -463,8 +463,17 @@
mBaseURL = tmp;
}
- CHECK_GT(mSessionDesc->countTracks(), 1u);
- setupTrack(1);
+ if (mSessionDesc->countTracks() < 2) {
+ // There's no actual tracks in this session.
+ // The first "track" is merely session meta
+ // data.
+
+ LOGW("Session doesn't contain any playable "
+ "tracks. Aborting.");
+ result = ERROR_UNSUPPORTED;
+ } else {
+ setupTrack(1);
+ }
}
}
}
@@ -783,9 +792,13 @@
}
if (mNumAccessUnitsReceived == 0) {
+#if 1
LOGI("stream ended? aborting.");
(new AMessage('abor', id()))->post();
break;
+#else
+ LOGI("haven't seen an AU in a looong time.");
+#endif
}
mNumAccessUnitsReceived = 0;
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
index 99cbb86..62213de 100644
--- a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
+++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
@@ -16,8 +16,7 @@
package com.android.nfc_extras;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
import android.nfc.INfcAdapterExtras;
import android.nfc.NfcAdapter;
import android.os.RemoteException;
@@ -60,10 +59,14 @@
// best effort recovery
private static NfcAdapter sAdapter;
private static INfcAdapterExtras sService;
- private static NfcAdapterExtras sSingleton;
- private static NfcExecutionEnvironment sEmbeddedEe;
- private static CardEmulationRoute sRouteOff;
- private static CardEmulationRoute sRouteOnWhenScreenOn;
+ private static final CardEmulationRoute ROUTE_OFF =
+ new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
+
+ private final NfcExecutionEnvironment mEmbeddedEe;
+ private final CardEmulationRoute mRouteOnWhenScreenOn;
+
+ final Context mContext;
+ final String mPackageName;
/** get service handles */
private static void initService() {
@@ -84,31 +87,35 @@
* @return the {@link NfcAdapterExtras} object for the given {@link NfcAdapter}
*/
public static NfcAdapterExtras get(NfcAdapter adapter) {
- synchronized(NfcAdapterExtras.class) {
- if (sSingleton == null) {
+ Context context = adapter.getContext();
+ if (context == null) {
+ throw new UnsupportedOperationException(
+ "You must pass a context to your NfcAdapter to use the NFC extras APIs");
+ }
+
+ synchronized (NfcAdapterExtras.class) {
+ if (sService == null) {
try {
sAdapter = adapter;
- sSingleton = new NfcAdapterExtras();
- sEmbeddedEe = new NfcExecutionEnvironment(sSingleton);
- sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
- sRouteOnWhenScreenOn = new CardEmulationRoute(
- CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe);
initService();
} finally {
if (sService == null) {
- sRouteOnWhenScreenOn = null;
- sRouteOff = null;
- sEmbeddedEe = null;
- sSingleton = null;
sAdapter = null;
}
}
}
- return sSingleton;
}
+
+ return new NfcAdapterExtras(context);
}
- private NfcAdapterExtras() {}
+ private NfcAdapterExtras(Context context) {
+ mContext = context.getApplicationContext();
+ mPackageName = context.getPackageName();
+ mEmbeddedEe = new NfcExecutionEnvironment(this);
+ mRouteOnWhenScreenOn = new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON,
+ mEmbeddedEe);
+ }
/**
* Immutable data class that describes a card emulation route.
@@ -166,18 +173,16 @@
*
* <p class="note">
* Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
- *
- * @return
*/
public CardEmulationRoute getCardEmulationRoute() {
try {
- int route = sService.getCardEmulationRoute();
+ int route = sService.getCardEmulationRoute(mPackageName);
return route == CardEmulationRoute.ROUTE_OFF ?
- sRouteOff :
- sRouteOnWhenScreenOn;
+ ROUTE_OFF :
+ mRouteOnWhenScreenOn;
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
- return sRouteOff;
+ return ROUTE_OFF;
}
}
@@ -189,11 +194,11 @@
* <p class="note">
* Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
*
- * @param route a {@link #CardEmulationRoute}
+ * @param route a {@link CardEmulationRoute}
*/
public void setCardEmulationRoute(CardEmulationRoute route) {
try {
- sService.setCardEmulationRoute(route.route);
+ sService.setCardEmulationRoute(mPackageName, route.route);
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
}
@@ -201,7 +206,7 @@
/**
* Get the {@link NfcExecutionEnvironment} that is embedded with the
- * {@link NFcAdapter}.
+ * {@link NfcAdapter}.
*
* <p class="note">
* Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
@@ -209,7 +214,7 @@
* @return a {@link NfcExecutionEnvironment}, or null if there is no embedded NFC-EE
*/
public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() {
- return sEmbeddedEe;
+ return mEmbeddedEe;
}
/**
@@ -218,12 +223,12 @@
* Some implementations of NFC Adapter Extras may require applications
* to authenticate with a token, before using other methods.
*
- * @param a implementation specific token
- * @throws a {@link java.lang.SecurityException} if authentication failed
+ * @param token a implementation specific token
+ * @throws java.lang.SecurityException if authentication failed
*/
public void authenticate(byte[] token) {
try {
- sService.authenticate(token);
+ sService.authenticate(mPackageName, token);
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
}
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
index 63c2de2..f47327a 100644
--- a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
+++ b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
@@ -16,20 +16,17 @@
package com.android.nfc_extras;
-import java.io.IOException;
-
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.content.Context;
-import android.nfc.INfcAdapterExtras;
-import android.nfc.NfcAdapter;
import android.os.Binder;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.RemoteException;
+import java.io.IOException;
+
public class NfcExecutionEnvironment {
private final NfcAdapterExtras mExtras;
+ private final Binder mToken;
/**
* Broadcast Action: An ISO-DEP AID was selected.
@@ -115,6 +112,7 @@
NfcExecutionEnvironment(NfcAdapterExtras extras) {
mExtras = extras;
+ mToken = new Binder();
}
/**
@@ -133,7 +131,7 @@
*/
public void open() throws IOException {
try {
- Bundle b = mExtras.getService().open(new Binder());
+ Bundle b = mExtras.getService().open(mExtras.mPackageName, mToken);
throwBundle(b);
} catch (RemoteException e) {
mExtras.attemptDeadServiceRecovery(e);
@@ -151,7 +149,7 @@
*/
public void close() throws IOException {
try {
- throwBundle(mExtras.getService().close());
+ throwBundle(mExtras.getService().close(mExtras.mPackageName, mToken));
} catch (RemoteException e) {
mExtras.attemptDeadServiceRecovery(e);
throw new IOException("NFC Service was dead");
@@ -169,7 +167,7 @@
public byte[] transceive(byte[] in) throws IOException {
Bundle b;
try {
- b = mExtras.getService().transceive(in);
+ b = mExtras.getService().transceive(mExtras.mPackageName, in);
} catch (RemoteException e) {
mExtras.attemptDeadServiceRecovery(e);
throw new IOException("NFC Service was dead, need to re-open");
diff --git a/opengl/java/android/opengl/EGLLogWrapper.java b/opengl/java/android/opengl/EGLLogWrapper.java
index 6c0fdb3..36e88a2 100644
--- a/opengl/java/android/opengl/EGLLogWrapper.java
+++ b/opengl/java/android/opengl/EGLLogWrapper.java
@@ -314,6 +314,16 @@
checkError();
return result;
}
+
+ /** @hide **/
+ public boolean eglReleaseThread() {
+ begin("eglReleaseThread");
+ end();
+ boolean result = mEgl10.eglReleaseThread();
+ returns(result);
+ checkError();
+ return result;
+ }
public boolean eglSwapBuffers(EGLDisplay display, EGLSurface surface) {
begin("eglInitialize");
diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java
index 51d6ca8..6992019 100644
--- a/opengl/java/com/google/android/gles_jni/EGLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java
@@ -31,6 +31,8 @@
public native boolean eglInitialize(EGLDisplay display, int[] major_minor);
public native boolean eglQueryContext(EGLDisplay display, EGLContext context, int attribute, int[] value);
public native boolean eglQuerySurface(EGLDisplay display, EGLSurface surface, int attribute, int[] value);
+ /** @hide **/
+ public native boolean eglReleaseThread();
public native boolean eglChooseConfig(EGLDisplay display, int[] attrib_list, EGLConfig[] configs, int config_size, int[] num_config);
public native boolean eglGetConfigAttrib(EGLDisplay display, EGLConfig config, int attribute, int[] value);
public native boolean eglGetConfigs(EGLDisplay display, EGLConfig[] configs, int config_size, int[] num_config);
@@ -44,6 +46,9 @@
public native boolean eglCopyBuffers(EGLDisplay display, EGLSurface surface, Object native_pixmap);
public native boolean eglWaitGL();
public native boolean eglWaitNative(int engine, Object bindTarget);
+
+ /** @hide **/
+ public static native int getInitCount(EGLDisplay display);
public EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list) {
int eglContextId = _eglCreateContext(display, config, share_context, attrib_list);
@@ -85,7 +90,7 @@
eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
} else if (native_window instanceof SurfaceTexture) {
eglSurfaceId = _eglCreateWindowSurfaceTexture(display, config,
- (SurfaceTexture) native_window, attrib_list);
+ native_window, attrib_list);
} else {
throw new java.lang.UnsupportedOperationException(
"eglCreateWindowSurface() can only be called with an instance of " +
diff --git a/opengl/java/javax/microedition/khronos/egl/EGL10.java b/opengl/java/javax/microedition/khronos/egl/EGL10.java
index 2ae793a..cf58888 100644
--- a/opengl/java/javax/microedition/khronos/egl/EGL10.java
+++ b/opengl/java/javax/microedition/khronos/egl/EGL10.java
@@ -114,6 +114,8 @@
boolean eglQueryContext(EGLDisplay display, EGLContext context, int attribute, int[] value);
String eglQueryString(EGLDisplay display, int name);
boolean eglQuerySurface(EGLDisplay display, EGLSurface surface, int attribute, int[] value);
+ /** @hide **/
+ boolean eglReleaseThread();
boolean eglSwapBuffers(EGLDisplay display, EGLSurface surface);
boolean eglTerminate(EGLDisplay display);
boolean eglWaitGL();
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 1c1092c..e0a367d 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -91,6 +91,8 @@
inline bool isValid() const { return magic == '_dpy'; }
inline bool isAlive() const { return isValid(); }
+ inline uint32_t getRefsCount() const { return refs; }
+
struct strings_t {
char const * vendor;
char const * version;
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png
index d697c2f..cd9a54a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png
index 839c134..5661eaf 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png
index 4f8c987..98455cf 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 93ac22e..9be9041 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -51,7 +51,7 @@
android:visibility="gone"
android:id="@+id/spacer"
/>
- <FrameLayout
+ <!--<FrameLayout
android:id="@+id/wimax_combo"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -72,6 +72,7 @@
android:layout_gravity="center|bottom"
/>
</FrameLayout>
+ -->
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a0d7b13..fc81f8e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -257,10 +257,16 @@
<string name="accessibility_wifi_three_bars">Wi-Fi three bars.</string>
<!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wifi_signal_full">WiFi signal full.</string>
+
+ <!-- Content description of the WiMAX signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_no_wimax">No WiMAX.</string>
+ <!-- Content description of the WiMAX signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wimax_one_bar">WiMAX one bar.</string>
+ <!-- Content description of the WiMAX signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wimax_two_bars">WiMAX two bars.</string>
+ <!-- Content description of the WiMAX signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wimax_three_bars">WiMAX three bars.</string>
+ <!-- Content description of the WiMAX signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wimax_signal_full">WiMAX signal full.</string>
<!-- Content description of the data connection type GPRS for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
index 2e1803e..2be35b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
@@ -118,15 +118,20 @@
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.OPAQUE);
+ // We use a pixel format of RGB565 for the status bar to save memory bandwidth and
+ // to ensure that the layer can be handled by HWComposer. On some devices the
+ // HWComposer is unable to handle SW-rendered RGBX_8888 layers.
+ PixelFormat.RGB_565);
// the status bar should be in an overlay if possible
final Display defaultDisplay
= ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
- if (ActivityManager.isHighEndGfx(defaultDisplay)) {
- lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
- }
+
+ // We explicitly leave FLAG_HARDWARE_ACCELERATED out of the flags. The status bar occupies
+ // very little screen real-estate and is updated fairly frequently. By using CPU rendering
+ // for the status bar, we prevent the GPU from having to wake up just to do these small
+ // updates, which should help keep power consumption down.
lp.gravity = getStatusBarGravity();
lp.setTitle("StatusBar");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index b0e6968..51fb262 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -350,11 +350,11 @@
(SignalClusterView)sb.findViewById(R.id.signal_cluster);
mNetworkController.addSignalCluster(signalCluster);
signalCluster.setNetworkController(mNetworkController);
- final ImageView wimaxRSSI =
- (ImageView)sb.findViewById(R.id.wimax_signal);
- if (wimaxRSSI != null) {
- mNetworkController.addWimaxIconView(wimaxRSSI);
- }
+// final ImageView wimaxRSSI =
+// (ImageView)sb.findViewById(R.id.wimax_signal);
+// if (wimaxRSSI != null) {
+// mNetworkController.addWimaxIconView(wimaxRSSI);
+// }
// Recents Panel
mRecentTasksLoader = new RecentTasksLoader(context);
updateRecentsPanel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index f77e93f..55a5b0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -111,6 +111,7 @@
com.android.internal.R.drawable.stat_sys_tether_bluetooth;
//wimax
+ private boolean mWimaxSupported = false;
private boolean mIsWimaxEnabled = false;
private boolean mWimaxConnected = false;
private boolean mWimaxIdle = false;
@@ -213,9 +214,9 @@
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- boolean isWimaxConfigEnabled = mContext.getResources().getBoolean(
+ mWimaxSupported = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_wimaxEnabled);
- if(isWimaxConfigEnabled) {
+ if(mWimaxSupported) {
filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
@@ -262,19 +263,36 @@
public void addSignalCluster(SignalCluster cluster) {
mSignalClusters.add(cluster);
+ refreshSignalCluster(cluster);
+ }
+
+ public void refreshSignalCluster(SignalCluster cluster) {
cluster.setWifiIndicators(
mWifiConnected, // only show wifi in the cluster if connected
mWifiIconId,
mWifiActivityIconId,
mContentDescriptionWifi);
- cluster.setMobileDataIndicators(
- mHasMobileDataFeature,
- mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
- mMobileActivityIconId,
- mDataTypeIconId,
- mContentDescriptionPhoneSignal,
- mContentDescriptionDataType);
+ if (mIsWimaxEnabled && mWimaxConnected) {
+ // wimax is special
+ cluster.setMobileDataIndicators(
+ true,
+ mWimaxIconId,
+ mMobileActivityIconId,
+ mDataTypeIconId,
+ mContentDescriptionWimax,
+ mContentDescriptionDataType);
+ } else {
+ // normal mobile data
+ cluster.setMobileDataIndicators(
+ mHasMobileDataFeature,
+ mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
+ mMobileActivityIconId,
+ mDataTypeIconId,
+ mContentDescriptionPhoneSignal,
+ mContentDescriptionDataType);
+ }
+ cluster.setIsAirplaneMode(mAirplaneMode);
}
public void setStackedMode(boolean stacked) {
@@ -311,7 +329,7 @@
} else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
- updateWimaxState(intent);
+ updateWimaxState(intent);
refreshViews();
}
}
@@ -466,91 +484,100 @@
}
private final void updateDataNetType() {
- switch (mDataNetType) {
- case TelephonyManager.NETWORK_TYPE_UNKNOWN:
- if (!mShowAtLeastThreeGees) {
- mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
- mDataTypeIconId = 0;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_gprs);
- break;
- } else {
- // fall through
- }
- case TelephonyManager.NETWORK_TYPE_EDGE:
- if (!mShowAtLeastThreeGees) {
- mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_e;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_edge);
- break;
- } else {
- // fall through
- }
- case TelephonyManager.NETWORK_TYPE_UMTS:
- mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_3g);
- break;
- case TelephonyManager.NETWORK_TYPE_HSDPA:
- case TelephonyManager.NETWORK_TYPE_HSUPA:
- case TelephonyManager.NETWORK_TYPE_HSPA:
- case TelephonyManager.NETWORK_TYPE_HSPAP:
- if (mHspaDataDistinguishable) {
- mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_3_5g);
- } else {
+ if (mIsWimaxEnabled && mWimaxConnected) {
+ // wimax is a special 4g network not handled by telephony
+ mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_4g);
+ } else {
+ switch (mDataNetType) {
+ case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+ if (!mShowAtLeastThreeGees) {
+ mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+ mDataTypeIconId = 0;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_gprs);
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ if (!mShowAtLeastThreeGees) {
+ mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_e;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_edge);
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_UMTS:
mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3g);
- }
- break;
- case TelephonyManager.NETWORK_TYPE_CDMA:
- // display 1xRTT for IS95A/B
- mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_cdma);
- break;
- case TelephonyManager.NETWORK_TYPE_1xRTT:
- mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_cdma);
- break;
- case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
- case TelephonyManager.NETWORK_TYPE_EVDO_A:
- case TelephonyManager.NETWORK_TYPE_EVDO_B:
- case TelephonyManager.NETWORK_TYPE_EHRPD:
- mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_3g);
- break;
- case TelephonyManager.NETWORK_TYPE_LTE:
- mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_4g);
- break;
- default:
- if (!mShowAtLeastThreeGees) {
- mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_g;
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ if (mHspaDataDistinguishable) {
+ mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_3_5g);
+ } else {
+ mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_3g);
+ }
+ break;
+ case TelephonyManager.NETWORK_TYPE_CDMA:
+ // display 1xRTT for IS95A/B
+ mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_gprs);
- } else {
+ R.string.accessibility_data_connection_cdma);
+ break;
+ case TelephonyManager.NETWORK_TYPE_1xRTT:
+ mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_cdma);
+ break;
+ case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
+ case TelephonyManager.NETWORK_TYPE_EVDO_A:
+ case TelephonyManager.NETWORK_TYPE_EVDO_B:
+ case TelephonyManager.NETWORK_TYPE_EHRPD:
mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3g);
- }
- break;
+ break;
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_4g);
+ break;
+ default:
+ if (!mShowAtLeastThreeGees) {
+ mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_g;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_gprs);
+ } else {
+ mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_3g);
+ }
+ break;
+ }
}
+
if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
}
@@ -763,8 +790,7 @@
}
- // ===== Wimax ===================================================================
-
+ // ===== Wimax ===================================================================
private final void updateWimaxState(Intent intent) {
final String action = intent.getAction();
boolean wasConnected = mWimaxConnected;
@@ -772,42 +798,41 @@
int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
mIsWimaxEnabled = (wimaxStatus ==
- WimaxManagerConstants.NET_4G_STATE_ENABLED)? true : false;
+ WimaxManagerConstants.NET_4G_STATE_ENABLED);
} else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
} else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
- mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
+ mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
mWimaxExtraState = intent.getIntExtra(
WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
mWimaxConnected = (mWimaxState ==
- WimaxManagerConstants.WIMAX_STATE_CONNECTED) ? true : false;
- mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE)? true : false;
+ WimaxManagerConstants.WIMAX_STATE_CONNECTED);
+ mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
}
+ updateDataNetType();
updateWimaxIcons();
}
- private void updateWimaxIcons() {
- Slog.d(TAG, "in .... updateWimaxIcons function : "+mIsWimaxEnabled);
- if (mIsWimaxEnabled) {
- if (mWimaxConnected) {
- Slog.d(TAG, "in .... updateWimaxIcons function WiMAX COnnected");
- if (mWimaxIdle)
- mWimaxIconId = WimaxIcons.WIMAX_IDLE;
- else
- mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
- mContentDescriptionWimax = mContext.getString(
- AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
- } else {
- Slog.d(TAG, "in .... updateWimaxIcons function WiMAX Disconnected");
- mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
- mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
- }
- } else {
- Slog.d(TAG, "in .... updateWimaxIcons function wimax icon id 0");
- mWimaxIconId = 0;
- }
+
+ private void updateWimaxIcons() {
+ if (mIsWimaxEnabled) {
+ if (mWimaxConnected) {
+ if (mWimaxIdle)
+ mWimaxIconId = WimaxIcons.WIMAX_IDLE;
+ else
+ mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
+ mContentDescriptionWimax = mContext.getString(
+ AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
+ } else {
+ mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
+ mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
+ }
+ } else {
+ mWimaxIconId = 0;
}
+ }
+
// ===== Full or limited Internet connectivity ==================================
private void updateConnectivity(Intent intent) {
@@ -827,14 +852,14 @@
mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
- mBluetoothTethered = info.isConnected() ? true: false;
+ mBluetoothTethered = info.isConnected();
} else {
mBluetoothTethered = false;
}
// We want to update all the icons, all at once, for any condition change
updateDataNetType();
- updateWimaxIcons();
+ updateWimaxIcons();
updateDataIcon();
updateTelephonySignalStrength();
updateWifiIcons();
@@ -921,7 +946,7 @@
combinedSignalIconId = mDataSignalIconId;
}
- else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered) {
+ else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected) {
// pretty much totally disconnected
label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
@@ -961,23 +986,12 @@
if (mLastPhoneSignalIconId != mPhoneSignalIconId
|| mLastDataDirectionOverlayIconId != combinedActivityIconId
|| mLastWifiIconId != mWifiIconId
+ || mLastWimaxIconId != mWimaxIconId
|| mLastDataTypeIconId != mDataTypeIconId)
{
// NB: the mLast*s will be updated later
for (SignalCluster cluster : mSignalClusters) {
- cluster.setWifiIndicators(
- mWifiConnected, // only show wifi in the cluster if connected
- mWifiIconId,
- mWifiActivityIconId,
- mContentDescriptionWifi);
- cluster.setMobileDataIndicators(
- mHasMobileDataFeature,
- mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
- mMobileActivityIconId,
- mDataTypeIconId,
- mContentDescriptionPhoneSignal,
- mContentDescriptionDataType);
- cluster.setIsAirplaneMode(mAirplaneMode);
+ refreshSignalCluster(cluster);
}
}
@@ -1152,11 +1166,22 @@
pw.println(mWifiLevel);
pw.print(" mWifiSsid=");
pw.println(mWifiSsid);
- pw.print(String.format(" mWifiIconId=0x%08x/%s",
+ pw.println(String.format(" mWifiIconId=0x%08x/%s",
mWifiIconId, getResourceName(mWifiIconId)));
pw.print(" mWifiActivity=");
pw.println(mWifiActivity);
+ if (mWimaxSupported) {
+ pw.println(" - wimax ------");
+ pw.print(" mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
+ pw.print(" mWimaxConnected="); pw.println(mWimaxConnected);
+ pw.print(" mWimaxIdle="); pw.println(mWimaxIdle);
+ pw.println(String.format(" mWimaxIconId=0x%08x/%s",
+ mWimaxIconId, getResourceName(mWimaxIconId)));
+ pw.println(String.format(" mWimaxSignal=%d", mWimaxSignal));
+ pw.println(String.format(" mWimaxState=%d", mWimaxState));
+ pw.println(String.format(" mWimaxExtraState=%d", mWimaxExtraState));
+ }
pw.println(" - Bluetooth ----");
pw.print(" mBtReverseTethered=");
@@ -1190,7 +1215,7 @@
pw.print(" mLastDataTypeIconId=0x");
pw.print(Integer.toHexString(mLastDataTypeIconId));
pw.print("/");
- pw.println(getResourceName(mLastCombinedSignalIconId));
+ pw.println(getResourceName(mLastDataTypeIconId));
pw.print(" mLastLabel=");
pw.print(mLastLabel);
pw.println("");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
index 8605489..d3d4338 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -16,22 +16,13 @@
package com.android.systemui.statusbar.policy;
+import com.android.systemui.statusbar.policy.TelephonyIcons;
import com.android.systemui.R;
class WimaxIcons {
- static final int[][] WIMAX_SIGNAL_STRENGTH = {
- { R.drawable.stat_sys_data_wimax_signal_0,
- R.drawable.stat_sys_data_wimax_signal_1,
- R.drawable.stat_sys_data_wimax_signal_2,
- R.drawable.stat_sys_data_wimax_signal_3 },
- { R.drawable.stat_sys_data_wimax_signal_0_fully,
- R.drawable.stat_sys_data_wimax_signal_1_fully,
- R.drawable.stat_sys_data_wimax_signal_2_fully,
- R.drawable.stat_sys_data_wimax_signal_3_fully }
- };
+ static final int[][] WIMAX_SIGNAL_STRENGTH = TelephonyIcons.DATA_SIGNAL_STRENGTH;
- static final int WIMAX_DISCONNECTED =
- R.drawable.stat_sys_data_wimax_signal_disconnected;
- static final int WIMAX_IDLE = R.drawable.stat_sys_data_wimax_signal_idle;
- static final int WIFI_LEVEL_COUNT = WIMAX_SIGNAL_STRENGTH[0].length;
+ static final int WIMAX_DISCONNECTED = WIMAX_SIGNAL_STRENGTH[0][0];
+
+ static final int WIMAX_IDLE = WIMAX_DISCONNECTED; // XXX: unclear if we need a different icon
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ed9ba79..921f331 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -360,6 +360,9 @@
int mResettingSystemUiFlags = 0;
// Bits that we are currently always keeping cleared.
int mForceClearedSystemUiFlags = 0;
+ // What we last reported to system UI about whether the compatibility
+ // menu needs to be displayed.
+ boolean mLastFocusNeedsMenu = false;
FakeWindow mHideNavFakeWindow = null;
@@ -370,8 +373,6 @@
static final Rect mTmpNavigationFrame = new Rect();
WindowState mTopFullscreenOpaqueWindowState;
- WindowState mTopAppWindowState;
- WindowState mLastTopAppWindowState;
boolean mTopIsFullscreen;
boolean mForceStatusBar;
boolean mHideLockScreen;
@@ -2250,7 +2251,6 @@
/** {@inheritDoc} */
public void beginAnimationLw(int displayWidth, int displayHeight) {
mTopFullscreenOpaqueWindowState = null;
- mTopAppWindowState = null;
mForceStatusBar = false;
mHideLockScreen = false;
@@ -2288,12 +2288,6 @@
}
}
}
- if (mTopAppWindowState == null && win.isVisibleOrBehindKeyguardLw()) {
- if (attrs.type >= FIRST_APPLICATION_WINDOW
- && attrs.type <= LAST_APPLICATION_WINDOW) {
- mTopAppWindowState = win;
- }
- }
}
/** {@inheritDoc} */
@@ -2349,35 +2343,6 @@
mTopIsFullscreen = topIsFullscreen;
- if (mTopAppWindowState != null && mTopAppWindowState != mLastTopAppWindowState) {
- mLastTopAppWindowState = mTopAppWindowState;
-
- final boolean topNeedsMenu = (mTopAppWindowState.getAttrs().flags
- & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
-
- mHandler.post(new Runnable() {
- public void run() {
- if (mStatusBarService == null) {
- // This is the one that can not go away, but it doesn't come up
- // before the window manager does, so don't fail if it doesn't
- // exist. This works as long as no fullscreen windows come up
- // before the status bar service does.
- mStatusBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService("statusbar"));
- }
- final IStatusBarService sbs = mStatusBarService;
- if (mStatusBarService != null) {
- try {
- sbs.topAppWindowChanged(topNeedsMenu);
- } catch (RemoteException e) {
- // This should be impossible because we're in the same process.
- mStatusBarService = null;
- }
- }
- }
- });
- }
-
// Hide the key guard if a visible window explicitly specifies that it wants to be displayed
// when the screen is locked
if (mKeyguard != null) {
@@ -3711,10 +3676,13 @@
& ~mResettingSystemUiFlags
& ~mForceClearedSystemUiFlags;
int diff = visibility ^ mLastSystemUiFlags;
- if (diff == 0) {
+ final boolean needsMenu = (mFocusedWindow.getAttrs().flags
+ & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
+ if (diff == 0 && mLastFocusNeedsMenu == needsMenu) {
return 0;
}
mLastSystemUiFlags = visibility;
+ mLastFocusNeedsMenu = needsMenu;
mHandler.post(new Runnable() {
public void run() {
if (mStatusBarService == null) {
@@ -3724,6 +3692,7 @@
if (mStatusBarService != null) {
try {
mStatusBarService.setSystemUiVisibility(visibility);
+ mStatusBarService.topAppWindowChanged(needsMenu);
} catch (RemoteException e) {
// not much to be done
mStatusBarService = null;
@@ -3756,6 +3725,10 @@
pw.print(" mForceClearedSystemUiFlags=0x");
pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
}
+ if (mLastFocusNeedsMenu) {
+ pw.print(prefix); pw.print("mLastFocusNeedsMenu=");
+ pw.println(mLastFocusNeedsMenu);
+ }
pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
pw.print(" mDockMode="); pw.print(mDockMode);
pw.print(" mCarDockRotation="); pw.print(mCarDockRotation);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 4af6112..6e4aca7 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -514,7 +514,9 @@
continue;
}
mCurrentLinkProperties[netType] = null;
- if (mNetConfigs[netType].isDefault()) mNetTrackers[netType].reconnect();
+ if (mNetTrackers[netType] != null && mNetConfigs[netType].isDefault()) {
+ mNetTrackers[netType].reconnect();
+ }
}
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
@@ -1595,6 +1597,7 @@
if (checkType == prevNetType) continue;
if (mNetConfigs[checkType] == null) continue;
if (!mNetConfigs[checkType].isDefault()) continue;
+ if (mNetTrackers[checkType] == null) continue;
// Enabling the isAvailable() optimization caused mobile to not get
// selected if it was in the middle of error handling. Specifically
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 05d42ada..cd63090 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1669,7 +1669,7 @@
final void setFocusedActivityLocked(ActivityRecord r) {
if (mFocusedActivity != r) {
mFocusedActivity = r;
- mWindowManager.setFocusedApp(r, true);
+ mWindowManager.setFocusedApp(r.appToken, true);
}
}
@@ -2346,7 +2346,8 @@
// XXX we are not dealing with propagating grantedUriPermissions...
// those are not yet exposed to user code, so there is no need.
int res = mMainStack.startActivityLocked(r.app.thread, intent,
- r.resolvedType, null, 0, aInfo, resultTo, resultWho,
+ r.resolvedType, null, 0, aInfo,
+ resultTo != null ? resultTo.appToken : null, resultWho,
requestCode, -1, r.launchedFromUid, false, false, null);
Binder.restoreCallingIdentity(origId);
@@ -2429,10 +2430,10 @@
return;
}
final long origId = Binder.clearCallingIdentity();
- mWindowManager.setAppOrientation(r, requestedOrientation);
+ mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
Configuration config = mWindowManager.updateOrientationFromAppTokens(
mConfiguration,
- r.mayFreezeScreenLocked(r.app) ? r : null);
+ r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
if (config != null) {
r.frozenBeforeDestroy = true;
if (!updateConfigurationLocked(config, r, false)) {
@@ -2449,7 +2450,7 @@
if (r == null) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
- return mWindowManager.getAppOrientation(r);
+ return mWindowManager.getAppOrientation(r.appToken);
}
}
@@ -2515,7 +2516,7 @@
for (int i=0; i<activities.size(); i++) {
ActivityRecord r = activities.get(i);
if (!r.finishing) {
- int index = mMainStack.indexOfTokenLocked(r);
+ int index = mMainStack.indexOfTokenLocked(r.appToken);
if (index >= 0) {
mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED,
null, "finish-heavy");
@@ -2617,7 +2618,7 @@
int i;
for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r == token) {
+ if (r.appToken == token) {
return true;
}
if (r.fullscreen && !r.finishing) {
@@ -2705,9 +2706,9 @@
r.makeFinishing();
mMainStack.mHistory.remove(i);
r.takeFromHistory();
- mWindowManager.removeAppToken(r);
+ mWindowManager.removeAppToken(r.appToken);
if (VALIDATE_TOKENS) {
- mWindowManager.validateAppTokens(mMainStack.mHistory);
+ mMainStack.validateAppTokensLocked();
}
r.removeUriPermissionsLocked();
@@ -5173,10 +5174,10 @@
if (topThumbnail != null) {
if (localLOGV) Slog.v(TAG, "Requesting top thumbnail");
try {
- topThumbnail.requestThumbnail(topRecord);
+ topThumbnail.requestThumbnail(topRecord.appToken);
} catch (Exception e) {
Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
- sendPendingThumbnail(null, topRecord, null, null, true);
+ sendPendingThumbnail(null, topRecord.appToken, null, null, true);
}
}
@@ -5547,7 +5548,7 @@
TaskRecord lastTask = null;
for (int i=0; i<N; i++) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r == token) {
+ if (r.appToken == token) {
if (!onlyRoot || lastTask != r.task) {
return r.task.taskId;
}
@@ -5568,7 +5569,7 @@
for (int i=0; i<N; i++) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if (r.realActivity.equals(className)
- && r != token && lastTask != r.task) {
+ && r.appToken != token && lastTask != r.task) {
if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
null, "others")) {
i--;
@@ -7112,7 +7113,7 @@
// process, then terminate it to avoid getting in a loop.
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
- int index = mMainStack.indexOfTokenLocked(r);
+ int index = mMainStack.indexOfActivityLocked(r);
r.stack.finishActivityLocked(r, index,
Activity.RESULT_CANCELED, null, "crashed");
// Also terminate any activities below it that aren't yet
@@ -8631,8 +8632,8 @@
try {
TransferPipe tp = new TransferPipe();
try {
- r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r,
- innerPrefix, args);
+ r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
+ r.appToken, innerPrefix, args);
tp.go(fd);
} finally {
tp.kill();
@@ -9048,8 +9049,8 @@
try {
TransferPipe tp = new TransferPipe();
try {
- r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r,
- innerPrefix, args);
+ r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
+ r.appToken, innerPrefix, args);
// Short timeout, since blocking here can
// deadlock with the application.
tp.go(fd, 2000);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 00e6cb2..951a946 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -29,6 +29,7 @@
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
@@ -48,9 +49,10 @@
/**
* An entry in the history stack, representing an activity.
*/
-final class ActivityRecord extends IApplicationToken.Stub {
+final class ActivityRecord {
final ActivityManagerService service; // owner
final ActivityStack stack; // owner
+ final IApplicationToken.Stub appToken; // window manager token
final ActivityInfo info; // all about me
final int launchedFromUid; // always the uid who started the activity.
final Intent intent; // the original intent that generated us
@@ -200,6 +202,70 @@
}
}
+ static class Token extends IApplicationToken.Stub {
+ final WeakReference<ActivityRecord> weakActivity;
+
+ Token(ActivityRecord activity) {
+ weakActivity = new WeakReference<ActivityRecord>(activity);
+ }
+
+ @Override public void windowsDrawn() throws RemoteException {
+ ActivityRecord activity = weakActivity.get();
+ if (activity != null) {
+ activity.windowsDrawn();
+ }
+ }
+
+ @Override public void windowsVisible() throws RemoteException {
+ ActivityRecord activity = weakActivity.get();
+ if (activity != null) {
+ activity.windowsVisible();
+ }
+ }
+
+ @Override public void windowsGone() throws RemoteException {
+ ActivityRecord activity = weakActivity.get();
+ if (activity != null) {
+ activity.windowsGone();
+ }
+ }
+
+ @Override public boolean keyDispatchingTimedOut() throws RemoteException {
+ ActivityRecord activity = weakActivity.get();
+ if (activity != null) {
+ return activity.keyDispatchingTimedOut();
+ }
+ return false;
+ }
+
+ @Override public long getKeyDispatchingTimeout() throws RemoteException {
+ ActivityRecord activity = weakActivity.get();
+ if (activity != null) {
+ return activity.getKeyDispatchingTimeout();
+ }
+ return 0;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Token{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(' ');
+ sb.append(weakActivity.get());
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+ static ActivityRecord forToken(IBinder token) {
+ try {
+ return token != null ? ((Token)token).weakActivity.get() : null;
+ } catch (ClassCastException e) {
+ Slog.w(ActivityManagerService.TAG, "Bad activity token: " + token, e);
+ return null;
+ }
+ }
+
ActivityRecord(ActivityManagerService _service, ActivityStack _stack, ProcessRecord _caller,
int _launchedFromUid, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration,
@@ -207,6 +273,7 @@
boolean _componentSpecified) {
service = _service;
stack = _stack;
+ appToken = new Token(this);
info = aInfo;
launchedFromUid = _launchedFromUid;
intent = _intent;
@@ -445,7 +512,7 @@
ar.add(intent);
service.grantUriPermissionFromIntentLocked(callingUid, packageName,
intent, getUriPermissionsLocked());
- app.thread.scheduleNewIntent(ar, this);
+ app.thread.scheduleNewIntent(ar, appToken);
sent = true;
} catch (RemoteException e) {
Slog.w(ActivityManagerService.TAG,
@@ -470,14 +537,14 @@
void pauseKeyDispatchingLocked() {
if (!keysPaused) {
keysPaused = true;
- service.mWindowManager.pauseKeyDispatching(this);
+ service.mWindowManager.pauseKeyDispatching(appToken);
}
}
void resumeKeyDispatchingLocked() {
if (keysPaused) {
keysPaused = false;
- service.mWindowManager.resumeKeyDispatching(this);
+ service.mWindowManager.resumeKeyDispatching(appToken);
}
}
@@ -512,14 +579,14 @@
public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
if (mayFreezeScreenLocked(app)) {
- service.mWindowManager.startAppFreezingScreen(this, configChanges);
+ service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
}
}
public void stopFreezingScreenLocked(boolean force) {
if (force || frozenBeforeDestroy) {
frozenBeforeDestroy = false;
- service.mWindowManager.stopAppFreezingScreen(this, force);
+ service.mWindowManager.stopAppFreezingScreen(appToken, force);
}
}
@@ -687,7 +754,7 @@
}
if (app != null && app.thread != null) {
try {
- app.thread.scheduleSleeping(this, _sleeping);
+ app.thread.scheduleSleeping(appToken, _sleeping);
if (sleeping && !stack.mGoingToSleepActivities.contains(this)) {
stack.mGoingToSleepActivities.add(this);
}
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 8435eaa..c892cb1 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -145,7 +145,12 @@
* running) activities. It contains HistoryRecord objects.
*/
final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
-
+
+ /**
+ * Used for validating app tokens with window manager.
+ */
+ final ArrayList<IBinder> mValidateAppTokens = new ArrayList<IBinder>();
+
/**
* List of running activities, sorted by recent usage.
* The first entry in the list is the least recently used.
@@ -294,11 +299,11 @@
}
} break;
case PAUSE_TIMEOUT_MSG: {
- IBinder token = (IBinder)msg.obj;
+ ActivityRecord r = (ActivityRecord)msg.obj;
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
- Slog.w(TAG, "Activity pause timeout for " + token);
- activityPaused(token, true);
+ Slog.w(TAG, "Activity pause timeout for " + r);
+ activityPaused(r != null ? r.appToken : null, true);
} break;
case IDLE_TIMEOUT_MSG: {
if (mService.mDidDexOpt) {
@@ -310,20 +315,20 @@
}
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
- IBinder token = (IBinder)msg.obj;
- Slog.w(TAG, "Activity idle timeout for " + token);
- activityIdleInternal(token, true, null);
+ ActivityRecord r = (ActivityRecord)msg.obj;
+ Slog.w(TAG, "Activity idle timeout for " + r);
+ activityIdleInternal(r != null ? r.appToken : null, true, null);
} break;
case DESTROY_TIMEOUT_MSG: {
- IBinder token = (IBinder)msg.obj;
+ ActivityRecord r = (ActivityRecord)msg.obj;
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
- Slog.w(TAG, "Activity destroy timeout for " + token);
- activityDestroyed(token);
+ Slog.w(TAG, "Activity destroy timeout for " + r);
+ activityDestroyed(r != null ? r.appToken : null);
} break;
case IDLE_NOW_MSG: {
- IBinder token = (IBinder)msg.obj;
- activityIdleInternal(token, false, null);
+ ActivityRecord r = (ActivityRecord)msg.obj;
+ activityIdleInternal(r != null ? r.appToken : null, false, null);
} break;
case LAUNCH_TIMEOUT_MSG: {
if (mService.mDidDexOpt) {
@@ -397,7 +402,7 @@
while (i >= 0) {
ActivityRecord r = mHistory.get(i);
// Note: the taskId check depends on real taskId fields being non-zero
- if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
+ if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)) {
return r;
}
i--;
@@ -406,23 +411,17 @@
}
final int indexOfTokenLocked(IBinder token) {
- try {
- ActivityRecord r = (ActivityRecord)token;
- return mHistory.indexOf(r);
- } catch (ClassCastException e) {
- Slog.w(TAG, "Bad activity token: " + token, e);
- return -1;
- }
+ return mHistory.indexOf(ActivityRecord.forToken(token));
+ }
+
+ final int indexOfActivityLocked(ActivityRecord r) {
+ return mHistory.indexOf(r);
}
final ActivityRecord isInStackLocked(IBinder token) {
- try {
- ActivityRecord r = (ActivityRecord)token;
- if (mHistory.contains(r)) {
- return r;
- }
- } catch (ClassCastException e) {
- Slog.w(TAG, "Bad activity token: " + token, e);
+ ActivityRecord r = ActivityRecord.forToken(token);
+ if (mHistory.contains(r)) {
+ return r;
}
return null;
}
@@ -517,7 +516,7 @@
throws RemoteException {
r.startFreezingScreenLocked(app, 0);
- mService.mWindowManager.setAppVisibility(r, true);
+ mService.mWindowManager.setAppVisibility(r.appToken, true);
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order. Note that
@@ -528,7 +527,7 @@
if (checkConfig) {
Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
- r.mayFreezeScreenLocked(app) ? r : null);
+ r.mayFreezeScreenLocked(app) ? r.appToken : null);
mService.updateConfigurationLocked(config, r, false);
}
@@ -590,7 +589,7 @@
profileFd = null;
}
}
- app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
+ app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, mService.mConfiguration,
r.compat, r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward(), profileFile, profileFd,
@@ -624,7 +623,7 @@
+ r.intent.getComponent().flattenToShortString()
+ ", giving up", e);
mService.appDiedLocked(app, app.pid, app.thread);
- requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
+ requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"2nd-crash");
return false;
}
@@ -821,7 +820,7 @@
}
if (w > 0) {
- return mService.mWindowManager.screenshotApplications(who, w, h);
+ return mService.mWindowManager.screenshotApplications(who.appToken, w, h);
}
return null;
}
@@ -856,8 +855,8 @@
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
System.identityHashCode(prev),
prev.shortComponentName);
- prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
- prev.configChangeFlags);
+ prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
+ userLeaving, prev.configChangeFlags);
if (mMainStack) {
mService.updateUsageStats(prev, false);
}
@@ -1129,7 +1128,7 @@
if (!r.visible) {
if (DEBUG_VISBILITY) Slog.v(
TAG, "Starting and making visible: " + r);
- mService.mWindowManager.setAppVisibility(r, true);
+ mService.mWindowManager.setAppVisibility(r.appToken, true);
}
if (r != starting) {
startSpecificActivityLocked(r, false, false);
@@ -1153,10 +1152,10 @@
if (DEBUG_VISBILITY) Slog.v(
TAG, "Making visible and scheduling visibility: " + r);
try {
- mService.mWindowManager.setAppVisibility(r, true);
+ mService.mWindowManager.setAppVisibility(r.appToken, true);
r.sleeping = false;
r.app.pendingUiClean = true;
- r.app.thread.scheduleWindowVisibility(r, true);
+ r.app.thread.scheduleWindowVisibility(r.appToken, true);
r.stopFreezingScreenLocked(false);
} catch (Exception e) {
// Just skip on any failure; we'll make it
@@ -1195,13 +1194,13 @@
TAG, "Making invisible: " + r);
r.visible = false;
try {
- mService.mWindowManager.setAppVisibility(r, false);
+ mService.mWindowManager.setAppVisibility(r.appToken, false);
if ((r.state == ActivityState.STOPPING
|| r.state == ActivityState.STOPPED)
&& r.app != null && r.app.thread != null) {
if (DEBUG_VISBILITY) Slog.v(
TAG, "Scheduling invisibility: " + r);
- r.app.thread.scheduleWindowVisibility(r, false);
+ r.app.thread.scheduleWindowVisibility(r.appToken, false);
}
} catch (Exception e) {
// Just skip on any failure; we'll make it
@@ -1351,7 +1350,7 @@
// previous should actually be hidden depending on whether the
// new one is found to be full-screen or not.
if (prev.finishing) {
- mService.mWindowManager.setAppVisibility(prev, false);
+ mService.mWindowManager.setAppVisibility(prev.appToken, false);
if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
+ prev + ", waitingVisible="
+ (prev != null ? prev.waitingVisible : null)
@@ -1399,8 +1398,8 @@
? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
: WindowManagerPolicy.TRANSIT_TASK_CLOSE, false);
}
- mService.mWindowManager.setAppWillBeHidden(prev);
- mService.mWindowManager.setAppVisibility(prev, false);
+ mService.mWindowManager.setAppWillBeHidden(prev.appToken);
+ mService.mWindowManager.setAppVisibility(prev.appToken, false);
} else {
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare open transition: prev=" + prev);
@@ -1414,8 +1413,8 @@
}
}
if (false) {
- mService.mWindowManager.setAppWillBeHidden(prev);
- mService.mWindowManager.setAppVisibility(prev, false);
+ mService.mWindowManager.setAppWillBeHidden(prev.appToken);
+ mService.mWindowManager.setAppVisibility(prev.appToken, false);
}
} else if (mHistory.size() > 1) {
if (DEBUG_TRANSITION) Slog.v(TAG,
@@ -1433,7 +1432,7 @@
if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
// This activity is now becoming visible.
- mService.mWindowManager.setAppVisibility(next, true);
+ mService.mWindowManager.setAppVisibility(next.appToken, true);
ActivityRecord lastResumedActivity = mResumedActivity;
ActivityState lastState = next.state;
@@ -1457,7 +1456,7 @@
synchronized (mService) {
Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
- next.mayFreezeScreenLocked(next.app) ? next : null);
+ next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
if (config != null) {
next.frozenBeforeDestroy = true;
}
@@ -1496,12 +1495,12 @@
if (DEBUG_RESULTS) Slog.v(
TAG, "Delivering results to " + next
+ ": " + a);
- next.app.thread.scheduleSendResult(next, a);
+ next.app.thread.scheduleSendResult(next.appToken, a);
}
}
if (next.newIntents != null) {
- next.app.thread.scheduleNewIntent(next.newIntents, next);
+ next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
}
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
@@ -1511,7 +1510,7 @@
next.sleeping = false;
showAskCompatModeDialogLocked(next);
next.app.pendingUiClean = true;
- next.app.thread.scheduleResumeActivity(next,
+ next.app.thread.scheduleResumeActivity(next.appToken,
mService.isNextTransitionForward());
checkReadyForSleepLocked();
@@ -1528,7 +1527,7 @@
} else {
if (SHOW_APP_STARTING_PREVIEW && mMainStack) {
mService.mWindowManager.setAppStartingWindow(
- next, next.packageName, next.theme,
+ next.appToken, next.packageName, next.theme,
mService.compatibilityInfoForPackageLocked(
next.info.applicationInfo),
next.nonLocalizedLabel,
@@ -1549,7 +1548,7 @@
// If any exception gets thrown, toss away this
// activity and try the next one.
Slog.w(TAG, "Exception thrown during resume of " + next, e);
- requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
+ requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
"resume-exception");
return true;
}
@@ -1567,7 +1566,7 @@
} else {
if (SHOW_APP_STARTING_PREVIEW) {
mService.mWindowManager.setAppStartingWindow(
- next, next.packageName, next.theme,
+ next.appToken, next.packageName, next.theme,
mService.compatibilityInfoForPackageLocked(
next.info.applicationInfo),
next.nonLocalizedLabel,
@@ -1610,10 +1609,10 @@
}
mHistory.add(addPos, r);
r.putInHistory();
- mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
+ mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
return;
}
@@ -1677,7 +1676,7 @@
mNoAnimActivities.remove(r);
}
mService.mWindowManager.addAppToken(
- addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
+ addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen);
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
@@ -1705,19 +1704,20 @@
else if (prev.nowVisible) prev = null;
}
mService.mWindowManager.setAppStartingWindow(
- r, r.packageName, r.theme,
+ r.appToken, r.packageName, r.theme,
mService.compatibilityInfoForPackageLocked(
r.info.applicationInfo), r.nonLocalizedLabel,
- r.labelRes, r.icon, r.windowFlags, prev, showStartingIcon);
+ r.labelRes, r.icon, r.windowFlags,
+ prev != null ? prev.appToken : null, showStartingIcon);
}
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
- mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
+ mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
}
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
if (doResume) {
@@ -1725,6 +1725,15 @@
}
}
+ final void validateAppTokensLocked() {
+ mValidateAppTokens.clear();
+ mValidateAppTokens.ensureCapacity(mHistory.size());
+ for (int i=0; i<mHistory.size(); i++) {
+ mValidateAppTokens.add(mHistory.get(i).appToken);
+ }
+ mService.mWindowManager.validateAppTokens(mValidateAppTokens);
+ }
+
/**
* Perform a reset of the given task, if needed as part of launching it.
* Returns the new HistoryRecord at the top of the task.
@@ -1826,7 +1835,7 @@
if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+ " out to new task " + target.task);
}
- mService.mWindowManager.setAppGroupId(target, task.taskId);
+ mService.mWindowManager.setAppGroupId(target.appToken, task.taskId);
if (replyChainEnd < 0) {
replyChainEnd = targetI;
}
@@ -1849,11 +1858,11 @@
}
mHistory.remove(srcPos);
mHistory.add(dstPos, p);
- mService.mWindowManager.moveAppToken(dstPos, p);
- mService.mWindowManager.setAppGroupId(p, p.task.taskId);
+ mService.mWindowManager.moveAppToken(dstPos, p.appToken);
+ mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
dstPos++;
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
i++;
}
@@ -1985,10 +1994,10 @@
mHistory.add(lastReparentPos, p);
if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
+ " in to resetting task " + task);
- mService.mWindowManager.moveAppToken(lastReparentPos, p);
- mService.mWindowManager.setAppGroupId(p, p.task.taskId);
+ mService.mWindowManager.moveAppToken(lastReparentPos, p.appToken);
+ mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
}
replyChainEnd = -1;
@@ -2081,7 +2090,7 @@
if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
&& (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
if (!ret.finishing) {
- int index = indexOfTokenLocked(ret);
+ int index = indexOfTokenLocked(ret.appToken);
if (index >= 0) {
finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
null, "clear");
@@ -3007,7 +3016,7 @@
return res;
}
- resultTo = outActivity[0];
+ resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
}
}
} finally {
@@ -3065,7 +3074,7 @@
ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
list.add(new ResultInfo(resultWho, requestCode,
resultCode, data));
- r.app.thread.scheduleSendResult(r, list);
+ r.app.thread.scheduleSendResult(r.appToken, list);
return;
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending result to " + r, e);
@@ -3080,7 +3089,7 @@
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
- requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
+ requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"no-history");
}
} else if (r.app != null && r.app.thread != null) {
@@ -3098,9 +3107,9 @@
if (DEBUG_VISBILITY) Slog.v(
TAG, "Stopping visible=" + r.visible + " for " + r);
if (!r.visible) {
- mService.mWindowManager.setAppVisibility(r, false);
+ mService.mWindowManager.setAppVisibility(r.appToken, false);
}
- r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
+ r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
if (mService.isSleeping()) {
r.setSleeping(true);
}
@@ -3145,7 +3154,7 @@
// normal flow and hide it once we determine that it is
// hidden by the activities in front of it.
if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
- mService.mWindowManager.setAppVisibility(s, false);
+ mService.mWindowManager.setAppVisibility(s.appToken, false);
}
}
if ((!s.waitingVisible || mService.isSleeping()) && remove) {
@@ -3186,14 +3195,14 @@
boolean enableScreen = false;
synchronized (mService) {
- if (token != null) {
- mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
+ ActivityRecord r = ActivityRecord.forToken(token);
+ if (r != null) {
+ mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
}
// Get the activity record.
- int index = indexOfTokenLocked(token);
+ int index = indexOfActivityLocked(r);
if (index >= 0) {
- ActivityRecord r = mHistory.get(index);
res = r;
if (fromTimeout) {
@@ -3413,7 +3422,7 @@
: WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE, false);
// Tell window manager to prepare for this one to be removed.
- mService.mWindowManager.setAppVisibility(r, false);
+ mService.mWindowManager.setAppVisibility(r.appToken, false);
if (mPausingActivity == null) {
if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
@@ -3440,7 +3449,7 @@
private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
int mode) {
- final int index = indexOfTokenLocked(r);
+ final int index = indexOfActivityLocked(r);
if (index < 0) {
return null;
}
@@ -3570,9 +3579,9 @@
if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
+ " (removed from history)");
r.state = ActivityState.DESTROYED;
- mService.mWindowManager.removeAppToken(r);
+ mService.mWindowManager.removeAppToken(r.appToken);
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
cleanUpActivityServicesLocked(r);
r.removeUriPermissionsLocked();
@@ -3653,7 +3662,7 @@
try {
if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
- r.app.thread.scheduleDestroyActivity(r, r.finishing,
+ r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
r.configChangeFlags);
} catch (Exception e) {
// We can just ignore exceptions here... if the process
@@ -3712,11 +3721,13 @@
final void activityDestroyed(IBinder token) {
synchronized (mService) {
- mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
+ ActivityRecord r = ActivityRecord.forToken(token);
+ if (r != null) {
+ mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
+ }
- int index = indexOfTokenLocked(token);
+ int index = indexOfActivityLocked(r);
if (index >= 0) {
- ActivityRecord r = mHistory.get(index);
if (r.state == ActivityState.DESTROYING) {
final long origId = Binder.clearCallingIdentity();
removeActivityFromHistoryLocked(r);
@@ -3781,7 +3792,7 @@
return;
}
- ArrayList moved = new ArrayList();
+ ArrayList<IBinder> moved = new ArrayList<IBinder>();
// Applying the affinities may have removed entries from the history,
// so get the size again.
@@ -3803,7 +3814,7 @@
}
mHistory.remove(pos);
mHistory.add(top, r);
- moved.add(0, r);
+ moved.add(0, r.appToken);
top--;
}
pos--;
@@ -3826,7 +3837,7 @@
mService.mWindowManager.moveAppTokensToTop(moved);
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
finishTaskMoveLocked(task);
@@ -3873,7 +3884,7 @@
}
}
- ArrayList moved = new ArrayList();
+ ArrayList<IBinder> moved = new ArrayList<IBinder>();
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare to back transition: task=" + task);
@@ -3898,7 +3909,7 @@
}
mHistory.remove(pos);
mHistory.add(bottom, r);
- moved.add(r);
+ moved.add(r.appToken);
bottom++;
}
pos++;
@@ -3918,7 +3929,7 @@
}
mService.mWindowManager.moveAppTokensToBottom(moved);
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
finishTaskMoveLocked(task);
@@ -4148,7 +4159,7 @@
if (r.app != null && r.app.thread != null) {
try {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
- r.app.thread.scheduleActivityConfigurationChanged(r);
+ r.app.thread.scheduleActivityConfigurationChanged(r.appToken);
} catch (RemoteException e) {
// If process died, whatever.
}
@@ -4178,7 +4189,7 @@
try {
if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
r.forceNewConfig = false;
- r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
+ r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents,
changes, !andResume, mService.mConfiguration);
// Note: don't need to call pauseIfSleepingLocked() here, because
// the caller will only pass in 'andResume' if this activity is
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 423a78f..c344bc6 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -73,7 +73,7 @@
private Context mContext;
private final static String TAG = "Tethering";
private final static boolean DBG = true;
- private final static boolean VDBG = true;
+ private final static boolean VDBG = false;
// TODO - remove both of these - should be part of interface inspection/selection stuff
private String[] mTetherableUsbRegexs;
@@ -228,7 +228,7 @@
if (isUsb(iface)) {
// ignore usb0 down after enabling RNDIS
// we will handle disconnect in interfaceRemoved instead
- if (VDBG) Log.d(TAG, "ignoring interface down for " + iface);
+ if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
} else if (sm != null) {
sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
mIfaces.remove(iface);
@@ -298,7 +298,6 @@
mIfaces.put(iface, sm);
sm.start();
}
- if (VDBG) Log.d(TAG, "interfaceAdded :" + iface);
}
public void interfaceRemoved(String iface) {
@@ -415,7 +414,7 @@
broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
erroredList);
mContext.sendStickyBroadcast(broadcast);
- if (VDBG) {
+ if (DBG) {
Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " +
activeList.size() + ", " + erroredList.size());
}
@@ -865,7 +864,7 @@
@Override
public boolean processMessage(Message message) {
- if (VDBG) Log.d(TAG, "InitialState.processMessage what=" + message.what);
+ if (DBG) Log.d(TAG, "InitialState.processMessage what=" + message.what);
boolean retValue = true;
switch (message.what) {
case CMD_TETHER_REQUESTED:
@@ -906,7 +905,7 @@
}
@Override
public boolean processMessage(Message message) {
- if (VDBG) Log.d(TAG, "StartingState.processMessage what=" + message.what);
+ if (DBG) Log.d(TAG, "StartingState.processMessage what=" + message.what);
boolean retValue = true;
switch (message.what) {
// maybe a parent class?
@@ -985,7 +984,7 @@
@Override
public boolean processMessage(Message message) {
- if (VDBG) Log.d(TAG, "TetheredState.processMessage what=" + message.what);
+ if (DBG) Log.d(TAG, "TetheredState.processMessage what=" + message.what);
boolean retValue = true;
boolean error = false;
switch (message.what) {
@@ -1061,7 +1060,7 @@
ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
break;
}
- if (VDBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
+ if (DBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
sendTetherStateChangedBroadcast();
if (mUsb) {
if (!Tethering.this.configureUsbIface(false)) {
@@ -1296,7 +1295,7 @@
}
}
- if (VDBG) {
+ if (DBG) {
Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn ="
+ mPreferredUpstreamMobileApn + ", got type=" + upType);
}
@@ -1328,7 +1327,7 @@
}
protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
- if (VDBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
+ if (DBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
mUpstreamIfaceName = ifaceName;
for (Object o : mNotifyList) {
TetherInterfaceSM sm = (TetherInterfaceSM)o;
@@ -1344,7 +1343,7 @@
}
@Override
public boolean processMessage(Message message) {
- if (VDBG) Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
+ if (DBG) Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
boolean retValue = true;
switch (message.what) {
case CMD_TETHER_MODE_REQUESTED:
@@ -1386,7 +1385,7 @@
}
@Override
public boolean processMessage(Message message) {
- if (VDBG) Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
+ if (DBG) Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
boolean retValue = true;
switch (message.what) {
case CMD_TETHER_MODE_REQUESTED:
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 77b0d96..6365525 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -806,9 +806,7 @@
final NetworkStats networkDevSnapshot;
try {
// collect any tethering stats
- final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
- final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering(
- tetheredIfacePairs);
+ final NetworkStats tetherSnapshot = getNetworkStatsTethering();
// record uid stats, folding in tethering stats
uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
@@ -1505,7 +1503,7 @@
NetworkStats before, NetworkStats current, boolean collectStale, String type) {
if (before != null) {
try {
- return current.subtract(before);
+ return current.subtract(before, false);
} catch (NonMonotonicException e) {
Log.w(TAG, "found non-monotonic values; saving to dropbox");
@@ -1517,8 +1515,13 @@
builder.append("right=").append(e.right).append('\n');
mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
- // return empty delta to avoid recording broken stats
- return new NetworkStats(0L, 10);
+ try {
+ // return clamped delta to help recover
+ return current.subtract(before, true);
+ } catch (NonMonotonicException e1) {
+ Log.wtf(TAG, "found non-monotonic values; returning empty delta", e1);
+ return new NetworkStats(0L, 10);
+ }
}
} else if (collectStale) {
// caller is okay collecting stale stats for first call.
@@ -1530,6 +1533,20 @@
}
}
+ /**
+ * Return snapshot of current tethering statistics. Will return empty
+ * {@link NetworkStats} if any problems are encountered.
+ */
+ private NetworkStats getNetworkStatsTethering() throws RemoteException {
+ try {
+ final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
+ return mNetworkManager.getNetworkStatsTethering(tetheredIfacePairs);
+ } catch (IllegalStateException e) {
+ Log.wtf(TAG, "problem reading network stats", e);
+ return new NetworkStats(0L, 10);
+ }
+ }
+
private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) {
return uidSnapshot.groupedByIface();
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 4ffc201..50321b3 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -3070,7 +3070,7 @@
// Application Window Tokens
// -------------------------------------------------------------
- public void validateAppTokens(List tokens) {
+ public void validateAppTokens(List<IBinder> tokens) {
int v = tokens.size()-1;
int m = mAppTokens.size()-1;
while (v >= 0 && m >= 0) {