+
#include "dumpstate.h"
static char* const gzip_args[] = { "gzip", "-6", 0 };
@@ -182,6 +186,8 @@ int main(int argc, char *argv[]) {
pid_t pid;
gid_t groups[] = { AID_LOG, AID_SDCARD_RW };
+ LOGI("begin\n");
+
/* set as high priority, and protect from OOM killer */
setpriority(PRIO_PROCESS, 0, -20);
protect_from_oom_killer();
@@ -332,6 +338,8 @@ int main(int argc, char *argv[]) {
/* so gzip will terminate */
close(STDOUT_FILENO);
+ LOGI("done\n");
+
return 0;
}
diff --git a/core/java/android/accounts/AccountAuthenticatorResponse.java b/core/java/android/accounts/AccountAuthenticatorResponse.java
index 3488c5e1dfba3..7c09fbffb86ad 100644
--- a/core/java/android/accounts/AccountAuthenticatorResponse.java
+++ b/core/java/android/accounts/AccountAuthenticatorResponse.java
@@ -22,8 +22,7 @@ import android.os.Parcel;
import android.os.RemoteException;
/**
- * Object that wraps calls to an {@link IAccountAuthenticatorResponse} object.
- * TODO: this interface is still in flux
+ * Object used to communicate responses back to the AccountManager
*/
public class AccountAuthenticatorResponse implements Parcelable {
private IAccountAuthenticatorResponse mAccountAuthenticatorResponse;
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index ae6d9140c2921..d03244977de2f 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -44,8 +44,7 @@ import com.google.android.collect.Maps;
/**
* A class that helps with interactions with the AccountManagerService. It provides
* methods to allow for account, password, and authtoken management for all accounts on the
- * device. Some of these calls are implemented with the help of the corresponding
- * {@link IAccountAuthenticator} services. One accesses the {@link AccountManager} by calling:
+ * device. One accesses the {@link AccountManager} by calling:
* AccountManager accountManager = AccountManager.get(context);
*
*
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b4ac159ea4ceb..2cd223fc0409d 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -653,7 +653,7 @@ public final class ActivityThread {
mStrongRef = strong ? rd : null;
}
public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean ordered) {
+ String data, Bundle extras, boolean ordered, boolean sticky) {
ReceiverDispatcher rd = mDispatcher.get();
if (DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
@@ -661,7 +661,8 @@ public final class ActivityThread {
+ " to " + rd);
}
if (rd != null) {
- rd.performReceive(intent, resultCode, data, extras, ordered);
+ rd.performReceive(intent, resultCode, data, extras,
+ ordered, sticky);
}
}
}
@@ -681,6 +682,7 @@ public final class ActivityThread {
private String mCurData;
private Bundle mCurMap;
private boolean mCurOrdered;
+ private boolean mCurSticky;
public void run() {
BroadcastReceiver receiver = mReceiver;
@@ -706,6 +708,7 @@ public final class ActivityThread {
receiver.setResult(mCurCode, mCurData, mCurMap);
receiver.clearAbortBroadcast();
receiver.setOrderedHint(mCurOrdered);
+ receiver.setInitialStickyHint(mCurSticky);
receiver.onReceive(mContext, intent);
} catch (Exception e) {
if (mRegistered && mCurOrdered) {
@@ -788,7 +791,7 @@ public final class ActivityThread {
}
public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean ordered) {
+ String data, Bundle extras, boolean ordered, boolean sticky) {
if (DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Log.i(TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
@@ -800,6 +803,7 @@ public final class ActivityThread {
args.mCurData = data;
args.mCurMap = extras;
args.mCurOrdered = ordered;
+ args.mCurSticky = sticky;
if (!mActivityThread.post(args)) {
if (mRegistered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
@@ -1515,9 +1519,9 @@ public final class ActivityThread {
// correctly ordered, since these are one-way calls and the binder driver
// applies transaction ordering per object for such calls.
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
- int resultCode, String dataStr, Bundle extras, boolean ordered)
- throws RemoteException {
- receiver.performReceive(intent, resultCode, dataStr, extras, ordered);
+ int resultCode, String dataStr, Bundle extras, boolean ordered,
+ boolean sticky) throws RemoteException {
+ receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky);
}
public void scheduleLowMemory() {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 928981d0c2d6c..a772a8f78ddf7 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -317,8 +317,9 @@ public abstract class ApplicationThreadNative extends Binder
String dataStr = data.readString();
Bundle extras = data.readBundle();
boolean ordered = data.readInt() != 0;
+ boolean sticky = data.readInt() != 0;
scheduleRegisteredReceiver(receiver, intent,
- resultCode, dataStr, extras, ordered);
+ resultCode, dataStr, extras, ordered, sticky);
return true;
}
@@ -716,7 +717,7 @@ class ApplicationThreadProxy implements IApplicationThread {
}
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
- int resultCode, String dataStr, Bundle extras, boolean ordered)
+ int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky)
throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -726,6 +727,7 @@ class ApplicationThreadProxy implements IApplicationThread {
data.writeString(dataStr);
data.writeBundle(extras);
data.writeInt(ordered ? 1 : 0);
+ data.writeInt(sticky ? 1 : 0);
mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 8dda8985d6be7..89a52fd70d50e 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -91,7 +91,7 @@ public interface IApplicationThread extends IInterface {
void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args)
throws RemoteException;
void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
- int resultCode, String data, Bundle extras, boolean ordered)
+ int resultCode, String data, Bundle extras, boolean ordered, boolean sticky)
throws RemoteException;
void scheduleLowMemory() throws RemoteException;
void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 18d9b92fbc5cd..be1dc4acb150d 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -147,7 +147,7 @@ public final class PendingIntent implements Parcelable {
mHandler = handler;
}
public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean serialized) {
+ String data, Bundle extras, boolean serialized, boolean sticky) {
mIntent = intent;
mResultCode = resultCode;
mResultData = data;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index e3ec2cc4cb24d..c6a0619cf8ec8 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -18,14 +18,19 @@ package android.bluetooth;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;
import java.io.IOException;
import java.util.Collections;
-import java.util.Set;
import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Random;
+import java.util.Set;
/**
* Represents the local Bluetooth adapter.
@@ -40,6 +45,7 @@ import java.util.HashSet;
*/
public final class BluetoothAdapter {
private static final String TAG = "BluetoothAdapter";
+ private static final boolean DBG = true; //STOPSHIP: Remove excess logging
/**
* Sentinel error value for this class. Guaranteed to not equal any other
@@ -557,33 +563,142 @@ public final class BluetoothAdapter {
return null;
}
+ /**
+ * Randomly picks RFCOMM channels until none are left.
+ * Avoids reserved channels.
+ */
+ private static class RfcommChannelPicker {
+ private static final int[] RESERVED_RFCOMM_CHANNELS = new int[] {
+ 10, // HFAG
+ 11, // HSAG
+ 12, // OPUSH
+ 19, // PBAP
+ };
+ private static LinkedList sChannels; // master list of non-reserved channels
+ private static Random sRandom;
+
+ private final LinkedList mChannels; // local list of channels left to try
+
+ public RfcommChannelPicker() {
+ synchronized (RfcommChannelPicker.class) {
+ if (sChannels == null) {
+ // lazy initialization of non-reserved rfcomm channels
+ sChannels = new LinkedList();
+ for (int i = 1; i <= BluetoothSocket.MAX_RFCOMM_CHANNEL; i++) {
+ sChannels.addLast(new Integer(i));
+ }
+ for (int reserved : RESERVED_RFCOMM_CHANNELS) {
+ sChannels.remove(new Integer(reserved));
+ }
+ sRandom = new Random();
+ }
+ mChannels = (LinkedList)sChannels.clone();
+ }
+ }
+ /* Returns next random channel, or -1 if we're out */
+ public int nextChannel() {
+ if (mChannels.size() == 0) {
+ return -1;
+ }
+ return mChannels.remove(sRandom.nextInt(mChannels.size()));
+ }
+ }
+
/**
* Create a listening, secure RFCOMM Bluetooth socket.
* A remote device connecting to this socket will be authenticated and
* communication on this socket will be encrypted.
*
Use {@link BluetoothServerSocket#accept} to retrieve incoming
- * connections to listening {@link BluetoothServerSocket}.
+ * connections from a listening {@link BluetoothServerSocket}.
*
Valid RFCOMM channels are in range 1 to 30.
- *
Requires {@link android.Manifest.permission#BLUETOOTH}
+ *
Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
* @param channel RFCOMM channel to listen on
* @return a listening RFCOMM BluetoothServerSocket
* @throws IOException on error, for example Bluetooth not available, or
* insufficient permissions, or channel in use.
+ * @hide
*/
public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
BluetoothServerSocket socket = new BluetoothServerSocket(
BluetoothSocket.TYPE_RFCOMM, true, true, channel);
- try {
- socket.mSocket.bindListen();
- } catch (IOException e) {
+ int errno = socket.mSocket.bindListen();
+ if (errno != 0) {
try {
socket.close();
- } catch (IOException e2) { }
- throw e;
+ } catch (IOException e) {}
+ socket.mSocket.throwErrnoNative(errno);
}
return socket;
}
+ /**
+ * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
+ *
A remote device connecting to this socket will be authenticated and
+ * communication on this socket will be encrypted.
+ *
Use {@link BluetoothServerSocket#accept} to retrieve incoming
+ * connections from a listening {@link BluetoothServerSocket}.
+ *
The system will assign an unused RFCOMM channel to listen on.
+ *
The system will also register a Service Discovery
+ * Protocol (SDP) record with the local SDP server containing the specified
+ * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
+ * can use the same UUID to query our SDP server and discover which channel
+ * to connect to. This SDP record will be removed when this socket is
+ * closed, or if this application closes unexpectedly.
+ *
Requires {@link android.Manifest.permission#BLUETOOTH}
+ * @param name service name for SDP record
+ * @param uuid uuid for SDP record
+ * @return a listening RFCOMM BluetoothServerSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions, or channel in use.
+ */
+ public BluetoothServerSocket listenUsingRfcomm(String name, ParcelUuid uuid)
+ throws IOException {
+ RfcommChannelPicker picker = new RfcommChannelPicker();
+
+ BluetoothServerSocket socket;
+ int channel;
+ int errno;
+ while (true) {
+ channel = picker.nextChannel();
+
+ if (channel == -1) {
+ throw new IOException("No available channels");
+ }
+
+ socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_RFCOMM, true, true, channel);
+ errno = socket.mSocket.bindListen();
+ if (errno == 0) {
+ if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel);
+ break; // success
+ } else if (errno == BluetoothSocket.EADDRINUSE) {
+ if (DBG) Log.d(TAG, "RFCOMM channel " + channel + " in use");
+ try {
+ socket.close();
+ } catch (IOException e) {}
+ continue; // try another channel
+ } else {
+ try {
+ socket.close();
+ } catch (IOException e) {}
+ socket.mSocket.throwErrnoNative(errno); // Exception as a result of bindListen()
+ }
+ }
+
+ int handle = -1;
+ try {
+ handle = mService.addRfcommServiceRecord(name, uuid, channel, new Binder());
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ if (handle == -1) {
+ try {
+ socket.close();
+ } catch (IOException e) {}
+ throw new IOException("Not able to register SDP record for " + name);
+ }
+ socket.setCloseHandler(mHandler, handle);
+ return socket;
+ }
+
/**
* Construct an unencrypted, unauthenticated, RFCOMM server socket.
* Call #accept to retrieve connections to this socket.
@@ -595,13 +710,12 @@ public final class BluetoothAdapter {
public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
BluetoothServerSocket socket = new BluetoothServerSocket(
BluetoothSocket.TYPE_RFCOMM, false, false, port);
- try {
- socket.mSocket.bindListen();
- } catch (IOException e) {
+ int errno = socket.mSocket.bindListen();
+ if (errno != 0) {
try {
socket.close();
- } catch (IOException e2) { }
- throw e;
+ } catch (IOException e) {}
+ socket.mSocket.throwErrnoNative(errno);
}
return socket;
}
@@ -617,13 +731,12 @@ public final class BluetoothAdapter {
public static BluetoothServerSocket listenUsingScoOn() throws IOException {
BluetoothServerSocket socket = new BluetoothServerSocket(
BluetoothSocket.TYPE_SCO, false, false, -1);
- try {
- socket.mSocket.bindListen();
- } catch (IOException e) {
+ int errno = socket.mSocket.bindListen();
+ if (errno != 0) {
try {
socket.close();
- } catch (IOException e2) { }
- throw e;
+ } catch (IOException e) {}
+ socket.mSocket.throwErrnoNative(errno);
}
return socket;
}
@@ -636,6 +749,17 @@ public final class BluetoothAdapter {
return Collections.unmodifiableSet(devices);
}
+ private Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ /* handle socket closing */
+ int handle = msg.what;
+ try {
+ if (DBG) Log.d(TAG, "Removing service record " + Integer.toHexString(handle));
+ mService.removeServiceRecord(handle);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ }
+ };
+
/**
* Validate a Bluetooth address, such as "00:43:A8:23:10:F0"
*
Alphabetic characters must be uppercase to be valid.
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 45dc432d332fe..d126ea48dddd5 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.os.Handler;
+
import java.io.Closeable;
import java.io.IOException;
@@ -38,7 +40,7 @@ import java.io.IOException;
* BluetoothSocket} ready for an outgoing connection to a remote
* {@link BluetoothDevice}.
*
- *
Use {@link BluetoothAdapter#listenUsingRfcommOn} to create a listening
+ *
Use {@link BluetoothAdapter#listenUsingRfcomm} to create a listening
* {@link BluetoothServerSocket} ready for incoming connections to the local
* {@link BluetoothAdapter}.
*
@@ -52,6 +54,8 @@ import java.io.IOException;
public final class BluetoothServerSocket implements Closeable {
/*package*/ final BluetoothSocket mSocket;
+ private Handler mHandler;
+ private int mMessage;
/**
* Construct a socket for incoming connections.
@@ -101,6 +105,16 @@ public final class BluetoothServerSocket implements Closeable {
* throw an IOException.
*/
public void close() throws IOException {
+ synchronized (this) {
+ if (mHandler != null) {
+ mHandler.obtainMessage(mMessage).sendToTarget();
+ }
+ }
mSocket.close();
}
+
+ /*package*/ synchronized void setCloseHandler(Handler handler, int message) {
+ mHandler = handler;
+ mMessage = message;
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index e462ea6383147..b9e33f3bda057 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -42,7 +42,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
* BluetoothSocket} ready for an outgoing connection to a remote
* {@link BluetoothDevice}.
*
- *
Use {@link BluetoothAdapter#listenUsingRfcommOn} to create a listening
+ *
Use {@link BluetoothAdapter#listenUsingRfcomm} to create a listening
* {@link BluetoothServerSocket} ready for incoming connections to the local
* {@link BluetoothAdapter}.
*
@@ -54,11 +54,17 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
* {@link android.Manifest.permission#BLUETOOTH}
*/
public final class BluetoothSocket implements Closeable {
+ /** @hide */
+ public static final int MAX_RFCOMM_CHANNEL = 30;
+
/** Keep TYPE_ fields in sync with BluetoothSocket.cpp */
/*package*/ static final int TYPE_RFCOMM = 1;
/*package*/ static final int TYPE_SCO = 2;
/*package*/ static final int TYPE_L2CAP = 3;
+ /*package*/ static final int EBADFD = 77;
+ /*package*/ static final int EADDRINUSE = 98;
+
private final int mType; /* one of TYPE_RFCOMM etc */
private final int mPort; /* RFCOMM channel or L2CAP psm */
private final BluetoothDevice mDevice; /* remote device */
@@ -90,6 +96,11 @@ public final class BluetoothSocket implements Closeable {
*/
/*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
BluetoothDevice device, int port) throws IOException {
+ if (type == BluetoothSocket.TYPE_RFCOMM) {
+ if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
+ throw new IOException("Invalid RFCOMM channel: " + port);
+ }
+ }
mType = type;
mAuth = auth;
mEncrypt = encrypt;
@@ -211,11 +222,15 @@ public final class BluetoothSocket implements Closeable {
return mOutputStream;
}
- /*package*/ void bindListen() throws IOException {
+ /**
+ * Currently returns unix errno instead of throwing IOException,
+ * so that BluetoothAdapter can check the error code for EADDRINUSE
+ */
+ /*package*/ int bindListen() {
mLock.readLock().lock();
try {
- if (mClosed) throw new IOException("socket closed");
- bindListenNative();
+ if (mClosed) return EBADFD;
+ return bindListenNative();
} finally {
mLock.readLock().unlock();
}
@@ -264,11 +279,16 @@ public final class BluetoothSocket implements Closeable {
private native void initSocketNative() throws IOException;
private native void initSocketFromFdNative(int fd) throws IOException;
private native void connectNative() throws IOException;
- private native void bindListenNative() throws IOException;
+ private native int bindListenNative();
private native BluetoothSocket acceptNative(int timeout) throws IOException;
private native int availableNative() throws IOException;
private native int readNative(byte[] b, int offset, int length) throws IOException;
private native int writeNative(byte[] b, int offset, int length) throws IOException;
private native void abortNative() throws IOException;
private native void destroyNative() throws IOException;
+ /**
+ * Throws an IOException for given posix errno. Done natively so we can
+ * use strerr to convert to string error.
+ */
+ /*package*/ native void throwErrnoNative(int errno) throws IOException;
}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index da0564a2a057a..4164a3d6e6658 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -50,6 +50,10 @@ public final class BluetoothUuid {
public static final ParcelUuid ObexObjectPush =
ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
+ public static final ParcelUuid[] RESERVED_UUIDS = {
+ AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
+ ObexObjectPush};
+
public static boolean isAudioSource(ParcelUuid uuid) {
return uuid.equals(AudioSource);
}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 2f77ba48da162..e54abec2de28d 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -63,4 +63,7 @@ interface IBluetooth
boolean setTrust(in String address, in boolean value);
boolean getTrustState(in String address);
+
+ int addRfcommServiceRecord(in String serviceName, in ParcelUuid uuid, int channel, IBinder b);
+ void removeServiceRecord(int handle);
}
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index b391c57df5ee6..b63d026c2b331 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -383,6 +383,24 @@ public abstract class BroadcastReceiver {
mAbortBroadcast = false;
}
+ /**
+ * Returns true if the receiver is currently processing an ordered
+ * broadcast.
+ */
+ public final boolean isOrderedBroadcast() {
+ return mOrderedHint;
+ }
+
+ /**
+ * Returns true if the receiver is currently processing the initial
+ * value of a sticky broadcast -- that is, the value that was last
+ * broadcast and is currently held in the sticky cache, so this is
+ * not directly the result of a broadcast right now.
+ */
+ public final boolean isInitialStickyBroadcast() {
+ return mInitialStickyHint;
+ }
+
/**
* For internal use, sets the hint about whether this BroadcastReceiver is
* running in ordered mode.
@@ -391,6 +409,14 @@ public abstract class BroadcastReceiver {
mOrderedHint = isOrdered;
}
+ /**
+ * For internal use, sets the hint about whether this BroadcastReceiver is
+ * receiving the initial sticky broadcast value. @hide
+ */
+ public final void setInitialStickyHint(boolean isInitialSticky) {
+ mInitialStickyHint = isInitialSticky;
+ }
+
/**
* Control inclusion of debugging help for mismatched
* calls to {@ Context#registerReceiver(BroadcastReceiver, IntentFilter)
@@ -414,7 +440,10 @@ public abstract class BroadcastReceiver {
}
void checkSynchronousHint() {
- if (mOrderedHint) {
+ // Note that we don't assert when receiving the initial sticky value,
+ // since that may have come from an ordered broadcast. We'll catch
+ // them later when the real broadcast happens again.
+ if (mOrderedHint || mInitialStickyHint) {
return;
}
RuntimeException e = new RuntimeException(
@@ -429,5 +458,6 @@ public abstract class BroadcastReceiver {
private boolean mAbortBroadcast;
private boolean mDebugUnregister;
private boolean mOrderedHint;
+ private boolean mInitialStickyHint;
}
diff --git a/core/java/android/content/IIntentReceiver.aidl b/core/java/android/content/IIntentReceiver.aidl
index 443db2d06d0f6..6f2f7c4053b48 100755
--- a/core/java/android/content/IIntentReceiver.aidl
+++ b/core/java/android/content/IIntentReceiver.aidl
@@ -28,6 +28,6 @@ import android.os.Bundle;
*/
oneway interface IIntentReceiver {
void performReceive(in Intent intent, int resultCode,
- String data, in Bundle extras, boolean ordered);
+ String data, in Bundle extras, boolean ordered, boolean sticky);
}
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index c8f7aa952d95e..e182021f8ef1b 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -113,7 +113,7 @@ public class IntentSender implements Parcelable {
mHandler = handler;
}
public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean serialized) {
+ String data, Bundle extras, boolean serialized, boolean sticky) {
mIntent = intent;
mResultCode = resultCode;
mResultData = data;
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index abfb27412de0c..7d2c698895817 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -413,6 +413,7 @@ public abstract class AsyncTask {
}
private void finish(Result result) {
+ if (isCancelled()) result = null;
onPostExecute(result);
mStatus = Status.FINISHED;
}
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index edf6d10b5dd20..93133d70255c8 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -28,6 +28,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothSocket;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetooth;
import android.os.ParcelUuid;
@@ -37,6 +38,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
+import android.os.IBinder;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
@@ -90,6 +92,8 @@ public class BluetoothService extends IBluetooth.Stub {
private final HashMap > mDeviceServiceChannelCache;
private final ArrayList mUuidIntentTracker;
+ private final HashMap mServiceRecordToPid;
+
static {
classInitNative();
}
@@ -117,6 +121,7 @@ public class BluetoothService extends IBluetooth.Stub {
mDeviceServiceChannelCache = new HashMap>();
mUuidIntentTracker = new ArrayList();
+ mServiceRecordToPid = new HashMap();
registerForAirplaneMode();
}
@@ -206,6 +211,7 @@ public class BluetoothService extends IBluetooth.Stub {
mIsDiscovering = false;
mAdapterProperties.clear();
+ mServiceRecordToPid.clear();
if (saveSetting) {
persistBluetoothOnSetting(false);
@@ -1211,6 +1217,71 @@ public class BluetoothService extends IBluetooth.Stub {
mDeviceServiceChannelCache.put(address, value);
}
+ /**
+ * b is a handle to a Binder instance, so that this service can be notified
+ * for Applications that terminate unexpectedly, to clean there service
+ * records
+ */
+ public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
+ int channel, IBinder b) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
+ "Need BLUETOOTH permission");
+ if (serviceName == null || uuid == null || channel < 1 ||
+ channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
+ return -1;
+ }
+ if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
+ Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
+ return -1;
+ }
+ int handle = addRfcommServiceRecordNative(serviceName,
+ uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
+ (short)channel);
+ if (DBG) log("new handle " + Integer.toHexString(handle));
+ if (handle == -1) {
+ return -1;
+ }
+
+ int pid = Binder.getCallingPid();
+ mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
+ try {
+ b.linkToDeath(new Reaper(handle, pid), 0);
+ } catch (RemoteException e) {}
+ return handle;
+ }
+
+ public void removeServiceRecord(int handle) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
+ "Need BLUETOOTH permission");
+ checkAndRemoveRecord(handle, Binder.getCallingPid());
+ }
+
+ private synchronized void checkAndRemoveRecord(int handle, int pid) {
+ Integer handleInt = new Integer(handle);
+ Integer owner = mServiceRecordToPid.get(handleInt);
+ if (owner != null && pid == owner.intValue()) {
+ if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " +
+ pid);
+ mServiceRecordToPid.remove(handleInt);
+ removeServiceRecordNative(handle);
+ }
+ }
+
+ private class Reaper implements IBinder.DeathRecipient {
+ int pid;
+ int handle;
+ Reaper(int handle, int pid) {
+ this.pid = pid;
+ this.handle = handle;
+ }
+ public void binderDied() {
+ synchronized (BluetoothService.this) {
+ if (DBG) log("Tracked app " + pid + " died");
+ checkAndRemoveRecord(handle, pid);
+ }
+ }
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -1263,25 +1334,25 @@ public class BluetoothService extends IBluetooth.Stub {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
-
switch(mBluetoothState) {
case BluetoothAdapter.STATE_OFF:
- pw.println("\nBluetooth OFF\n");
+ pw.println("Bluetooth OFF\n");
return;
case BluetoothAdapter.STATE_TURNING_ON:
- pw.println("\nBluetooth TURNING ON\n");
+ pw.println("Bluetooth TURNING ON\n");
return;
case BluetoothAdapter.STATE_TURNING_OFF:
- pw.println("\nBluetooth TURNING OFF\n");
+ pw.println("Bluetooth TURNING OFF\n");
return;
case BluetoothAdapter.STATE_ON:
- pw.println("\nBluetooth ON\n");
+ pw.println("Bluetooth ON\n");
}
- pw.println("\nLocal address = " + getAddress());
- pw.println("\nLocal name = " + getName());
- pw.println("\nisDiscovering() = " + isDiscovering());
+ pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
+
+ pw.println("Local address = " + getAddress());
+ pw.println("Local name = " + getName());
+ pw.println("isDiscovering() = " + isDiscovering());
BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
@@ -1292,13 +1363,17 @@ public class BluetoothService extends IBluetooth.Stub {
toBondStateString(bondState),
mBondState.getAttempt(address),
getRemoteName(address));
- if (bondState == BluetoothDevice.BOND_BONDED) {
- ParcelUuid[] uuids = getRemoteUuids(address);
- if (uuids == null) {
- pw.printf("\tuuids = null\n");
- } else {
- for (ParcelUuid uuid : uuids) {
- pw.printf("\t" + uuid + "\n");
+
+ Map uuidChannels = mDeviceServiceChannelCache.get(address);
+ if (uuidChannels == null) {
+ pw.println("\tuuids = null");
+ } else {
+ for (ParcelUuid uuid : uuidChannels.keySet()) {
+ Integer channel = uuidChannels.get(uuid);
+ if (channel == null) {
+ pw.println("\t" + uuid);
+ } else {
+ pw.println("\t" + uuid + " RFCOMM channel = " + channel);
}
}
}
@@ -1310,8 +1385,10 @@ public class BluetoothService extends IBluetooth.Stub {
devicesObjectPath = value.split(",");
}
pw.println("\n--ACL connected devices--");
- for (String device : devicesObjectPath) {
- pw.println(getAddressFromObjectPath(device));
+ if (devicesObjectPath != null) {
+ for (String device : devicesObjectPath) {
+ pw.println(getAddressFromObjectPath(device));
+ }
}
// Rather not do this from here, but no-where else and I need this
@@ -1331,10 +1408,15 @@ public class BluetoothService extends IBluetooth.Stub {
pw.println("getState() = STATE_ERROR");
break;
}
- pw.println("getCurrentHeadset() = " + headset.getCurrentHeadset());
- pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
+ pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset());
+ pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
headset.close();
+ pw.println("\n--Application Service Records--");
+ for (Integer handle : mServiceRecordToPid.keySet()) {
+ Integer pid = mServiceRecordToPid.get(handle);
+ pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
+ }
}
/* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
@@ -1423,8 +1505,12 @@ public class BluetoothService extends IBluetooth.Stub {
private native boolean setPasskeyNative(String address, int passkey, int nativeData);
private native boolean setPairingConfirmationNative(String address, boolean confirm,
int nativeData);
- private native boolean setDevicePropertyBooleanNative(String objectPath, String key, int value);
+ private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
+ int value);
private native boolean createDeviceNative(String address);
private native boolean discoverServicesNative(String objectPath, String pattern);
+ private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
+ short channel);
+ private native boolean removeServiceRecordNative(int handle);
}
diff --git a/core/jni/android_bluetooth_BluetoothSocket.cpp b/core/jni/android_bluetooth_BluetoothSocket.cpp
index 2532effe98bdc..31ebf8ca58cce 100644
--- a/core/jni/android_bluetooth_BluetoothSocket.cpp
+++ b/core/jni/android_bluetooth_BluetoothSocket.cpp
@@ -237,7 +237,8 @@ static void connectNative(JNIEnv *env, jobject obj) {
jniThrowIOException(env, ENOSYS);
}
-static void bindListenNative(JNIEnv *env, jobject obj) {
+/* Returns errno instead of throwing, so java can check errno */
+static int bindListenNative(JNIEnv *env, jobject obj) {
#ifdef HAVE_BLUETOOTH
LOGV(__FUNCTION__);
@@ -248,7 +249,7 @@ static void bindListenNative(JNIEnv *env, jobject obj) {
struct asocket *s = get_socketData(env, obj);
if (!s)
- return;
+ return EINVAL;
type = env->GetIntField(obj, field_mType);
@@ -283,28 +284,25 @@ static void bindListenNative(JNIEnv *env, jobject obj) {
memcpy(&addr_l2.l2_bdaddr, &bdaddr, sizeof(bdaddr_t));
break;
default:
- jniThrowIOException(env, ENOSYS);
- return;
+ return ENOSYS;
}
if (bind(s->fd, addr, addr_sz)) {
LOGV("...bind(%d) gave errno %d", s->fd, errno);
- jniThrowIOException(env, errno);
- return;
+ return errno;
}
if (listen(s->fd, 1)) {
LOGV("...listen(%d) gave errno %d", s->fd, errno);
- jniThrowIOException(env, errno);
- return;
+ return errno;
}
LOGV("...bindListenNative(%d) success", s->fd);
- return;
+ return 0;
#endif
- jniThrowIOException(env, ENOSYS);
+ return ENOSYS;
}
static jobject acceptNative(JNIEnv *env, jobject obj, int timeout) {
@@ -521,17 +519,22 @@ static void destroyNative(JNIEnv *env, jobject obj) {
jniThrowIOException(env, ENOSYS);
}
+static void throwErrnoNative(JNIEnv *env, jobject obj, jint err) {
+ jniThrowIOException(env, err);
+}
+
static JNINativeMethod sMethods[] = {
{"initSocketNative", "()V", (void*) initSocketNative},
{"initSocketFromFdNative", "(I)V", (void*) initSocketFromFdNative},
{"connectNative", "()V", (void *) connectNative},
- {"bindListenNative", "()V", (void *) bindListenNative},
+ {"bindListenNative", "()I", (void *) bindListenNative},
{"acceptNative", "(I)Landroid/bluetooth/BluetoothSocket;", (void *) acceptNative},
{"availableNative", "()I", (void *) availableNative},
{"readNative", "([BII)I", (void *) readNative},
{"writeNative", "([BII)I", (void *) writeNative},
{"abortNative", "()V", (void *) abortNative},
{"destroyNative", "()V", (void *) destroyNative},
+ {"throwErrnoNative", "(I)V", (void *) throwErrnoNative},
};
int register_android_bluetooth_BluetoothSocket(JNIEnv *env) {
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index c2f93eea868d3..ea64305d145f8 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -818,6 +818,48 @@ static jboolean discoverServicesNative(JNIEnv *env, jobject object,
return JNI_FALSE;
}
+static jint addRfcommServiceRecordNative(JNIEnv *env, jobject object,
+ jstring name, jlong uuidMsb, jlong uuidLsb, jshort channel) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_name = env->GetStringUTFChars(name, NULL);
+ LOGV("... name = %s", c_name);
+ LOGV("... uuid1 = %llX", uuidMsb);
+ LOGV("... uuid2 = %llX", uuidLsb);
+ LOGV("... channel = %d", channel);
+ DBusMessage *reply = dbus_func_args(env, nat->conn,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "AddRfcommServiceRecord",
+ DBUS_TYPE_STRING, &c_name,
+ DBUS_TYPE_UINT64, &uuidMsb,
+ DBUS_TYPE_UINT64, &uuidLsb,
+ DBUS_TYPE_UINT16, &channel,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(name, c_name);
+ return reply ? dbus_returns_uint32(env, reply) : -1;
+ }
+#endif
+ return -1;
+}
+
+static jboolean removeServiceRecordNative(JNIEnv *env, jobject object, jint handle) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ LOGV("... handle = %X", handle);
+ DBusMessage *reply = dbus_func_args(env, nat->conn,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "RemoveServiceRecord",
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+ return reply ? JNI_TRUE : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
@@ -861,6 +903,8 @@ static JNINativeMethod sMethods[] = {
(void *)setDevicePropertyBooleanNative},
{"createDeviceNative", "(Ljava/lang/String;)Z", (void *)createDeviceNative},
{"discoverServicesNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)discoverServicesNative},
+ {"addRfcommServiceRecordNative", "(Ljava/lang/String;JJS)I", (void *)addRfcommServiceRecordNative},
+ {"removeServiceRecordNative", "(I)Z", (void *)removeServiceRecordNative},
};
int register_android_server_BluetoothService(JNIEnv *env) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index cd39d0d8af246..34302b19b9e27 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8389,7 +8389,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (i == 0) {
finisher = new IIntentReceiver.Stub() {
public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean ordered)
+ String data, Bundle extras, boolean ordered,
+ boolean sticky)
throws RemoteException {
synchronized (ActivityManagerService.this) {
mDidUpdate = true;
@@ -11571,7 +11572,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Intent intent = (Intent)allSticky.get(i);
BroadcastRecord r = new BroadcastRecord(intent, null,
null, -1, -1, null, receivers, null, 0, null, null,
- false);
+ false, true);
if (mParallelBroadcasts.size() == 0) {
scheduleBroadcastsLocked();
}
@@ -11796,7 +11797,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
BroadcastRecord r = new BroadcastRecord(intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
registeredReceivers, resultTo, resultCode, resultData, map,
- ordered);
+ ordered, false);
if (DEBUG_BROADCAST) Log.v(
TAG, "Enqueueing parallel broadcast " + r
+ ": prev had " + mParallelBroadcasts.size());
@@ -11875,7 +11876,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|| resultTo != null) {
BroadcastRecord r = new BroadcastRecord(intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
- receivers, resultTo, resultCode, resultData, map, ordered);
+ receivers, resultTo, resultCode, resultData, map, ordered, false);
if (DEBUG_BROADCAST) Log.v(
TAG, "Enqueueing ordered broadcast " + r
+ ": prev had " + mOrderedBroadcasts.size());
@@ -12179,15 +12180,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
static void performReceive(ProcessRecord app, IIntentReceiver receiver,
- Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered) throws RemoteException {
+ Intent intent, int resultCode, String data, Bundle extras,
+ boolean ordered, boolean sticky) throws RemoteException {
if (app != null && app.thread != null) {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
- data, extras, ordered);
+ data, extras, ordered, sticky);
} else {
- receiver.performReceive(intent, resultCode, data, extras, ordered);
+ receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
}
}
@@ -12251,7 +12252,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
performReceive(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode,
- r.resultData, r.resultExtras, r.ordered);
+ r.resultData, r.resultExtras, r.ordered, r.sticky);
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
@@ -12384,7 +12385,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
performReceive(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
- r.resultData, r.resultExtras, false);
+ r.resultData, r.resultExtras, false, false);
} catch (RemoteException e) {
Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
}
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index da55049de7ada..db0a6cb3070b7 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -39,7 +39,9 @@ class BroadcastRecord extends Binder {
final String callerPackage; // who sent this
final int callingPid; // the pid of who sent this
final int callingUid; // the uid of who sent this
- String requiredPermission; // a permission the caller has required
+ final boolean ordered; // serialize the send to receivers?
+ final boolean sticky; // originated from existing sticky data?
+ final String requiredPermission; // a permission the caller has required
final List receivers; // contains BroadcastFilter and ResolveInfo
final IIntentReceiver resultTo; // who receives final result if non-null
long dispatchTime; // when dispatch started on this set of receivers
@@ -48,7 +50,6 @@ class BroadcastRecord extends Binder {
String resultData; // current result data value.
Bundle resultExtras; // current result extra data values.
boolean resultAbort; // current result abortBroadcast value.
- boolean ordered; // serialize the send to receivers?
int nextReceiver; // next receiver to be executed.
IBinder receiver; // who is currently running, null if none.
int state;
@@ -86,7 +87,7 @@ class BroadcastRecord extends Binder {
+ " resultCode=" + resultCode + " resultData=" + resultData);
pw.println(prefix + "resultExtras=" + resultExtras);
pw.println(prefix + "resultAbort=" + resultAbort
- + " ordered=" + ordered);
+ + " ordered=" + ordered + " sticky=" + sticky);
pw.println(prefix + "nextReceiver=" + nextReceiver
+ " receiver=" + receiver);
pw.println(prefix + "curFilter=" + curFilter);
@@ -122,7 +123,8 @@ class BroadcastRecord extends Binder {
BroadcastRecord(Intent _intent, ProcessRecord _callerApp, String _callerPackage,
int _callingPid, int _callingUid, String _requiredPermission,
List _receivers, IIntentReceiver _resultTo, int _resultCode,
- String _resultData, Bundle _resultExtras, boolean _serialized) {
+ String _resultData, Bundle _resultExtras, boolean _serialized,
+ boolean _sticky) {
intent = _intent;
callerApp = _callerApp;
callerPackage = _callerPackage;
@@ -135,6 +137,7 @@ class BroadcastRecord extends Binder {
resultData = _resultData;
resultExtras = _resultExtras;
ordered = _serialized;
+ sticky = _sticky;
nextReceiver = 0;
state = IDLE;
}
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index a753d059177dc..b3086d51fe360 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -248,7 +248,7 @@ class PendingIntentRecord extends IIntentSender.Stub {
if (sendFinish) {
try {
finishedReceiver.performReceive(new Intent(finalIntent), 0,
- null, null, false);
+ null, null, false, false);
} catch (RemoteException e) {
}
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
index d9cc2c62d1505..f49b5029189bb 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
@@ -135,7 +135,7 @@ public class CdmaSmsAddress extends SmsAddress {
};
private static final char[] numericCharsSugar = {
- '(', ')', ' ', '-', '+'
+ '(', ')', ' ', '-', '+', '.'
};
private static final SparseBooleanArray numericCharDialableMap = new SparseBooleanArray (
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index 4a77e1968ca08..85840a89358d8 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -61,6 +61,16 @@ public class CdmaSmsTest extends AndroidTestCase {
for (int i = 0; i < data2.length; i++) {
assertEquals(addr.origBytes[i], data2[i]);
}
+ addr = CdmaSmsAddress.parse("650.253.1000");
+ assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
+ assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
+ assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
+ assertEquals(addr.numberOfDigits, 10);
+ assertEquals(addr.origBytes.length, 10);
+ byte[] data5 = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10};
+ for (int i = 0; i < data2.length; i++) {
+ assertEquals(addr.origBytes[i], data5[i]);
+ }
addr = CdmaSmsAddress.parse("(+886) 917 222 555");
assertEquals(addr.ton, CdmaSmsAddress.TON_INTERNATIONAL_OR_IP);
assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeTest.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeTest.java
index e424f1d801851..c66ae37e70bc2 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeTest.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeTest.java
@@ -73,6 +73,48 @@ public class BridgeTest extends TestCase {
}
}
+ /**
+ * Mock implementation of {@link IStyleResourceValue}.
+ */
+ private static class StyleResourceValueMock extends ResourceValue
+ implements IStyleResourceValue {
+
+ private String mParentStyle = null;
+ private HashMap mItems = new HashMap();
+
+ StyleResourceValueMock(String name) {
+ super(name);
+ }
+
+ StyleResourceValueMock(String name, String parentStyle) {
+ super(name);
+ mParentStyle = parentStyle;
+ }
+
+ public String getParentStyle() {
+ return mParentStyle;
+ }
+
+ public IResourceValue findItem(String name) {
+ return mItems.get(name);
+ }
+
+ public void addItem(IResourceValue value) {
+ mItems.put(value.getName(), value);
+ }
+
+ @Override
+ public void replaceWith(ResourceValue value) {
+ super.replaceWith(value);
+
+ if (value instanceof StyleResourceValueMock) {
+ mItems.clear();
+ mItems.putAll(((StyleResourceValueMock)value).mItems);
+ }
+ }
+ }
+
+
public void testComputeLayout() throws Exception {
TestParser parser = new TestParser();
@@ -88,8 +130,10 @@ public class BridgeTest extends TestCase {
// FIXME need a dummy font for the tests!
ILayoutResult result = mBridge.computeLayout(parser, new Integer(1) /* projectKey */,
- screenWidth, screenHeight,
- "Theme", projectResources, frameworkResources, null, null);
+ screenWidth, screenHeight, false /* full render */,
+ 160, 160f, 160f,
+ "Theme", false /* is project theme */,
+ projectResources, frameworkResources, null, null);
display(result.getRootView(), "");
}
@@ -191,7 +235,7 @@ public class BridgeTest extends TestCase {
* a style item value. If the number of string in the array is not even, an exception is thrown.
*/
private IStyleResourceValue createStyle(String styleName, String... items) {
- StyleResourceValue value = new StyleResourceValue(styleName);
+ StyleResourceValueMock value = new StyleResourceValueMock(styleName);
if (items.length % 3 == 0) {
for (int i = 0 ; i < items.length;) {
@@ -220,8 +264,10 @@ public class BridgeTest extends TestCase {
// FIXME need a dummy font for the tests!
ILayoutResult result = mBridge.computeLayout(parser, new Integer(1) /* projectKey */,
- screenWidth, screenHeight,
- "Theme", projectResources, frameworkResources, null, null);
+ screenWidth, screenHeight, false /* full render */,
+ 160, 160f, 160f,
+ "Theme", false /* is project theme */,
+ projectResources, frameworkResources, null, null);
display(result.getRootView(), "");
}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java
index cac1f95df2c2b..ef7442c4a5ca6 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java
@@ -41,7 +41,7 @@ public class BridgeXmlBlockParserTest extends TestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
- URL url = this.getClass().getClassLoader().getResource("data/layout1.xml");
+ URL url = this.getClass().getClassLoader().getResource("layout1.xml");
mXmlPath = url.getFile();
mDoc = getXmlDocument(mXmlPath);
}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java
index 67ec5e16241f2..e667472c75db8 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java
@@ -12,7 +12,7 @@ public class NinePatchTest extends TestCase {
@Override
protected void setUp() throws Exception {
- URL url = this.getClass().getClassLoader().getResource("data/button.9.png");
+ URL url = this.getClass().getClassLoader().getResource("button.9.png");
mPatch = NinePatch.load(url, false /* convert */);
}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/StyleResourceValue.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/StyleResourceValue.java
deleted file mode 100644
index 84bdc2f03c92d..0000000000000
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/StyleResourceValue.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge;
-
-import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.api.IStyleResourceValue;
-
-import java.util.HashMap;
-
-class StyleResourceValue extends ResourceValue implements IStyleResourceValue {
-
- private String mParentStyle = null;
- private HashMap mItems = new HashMap();
-
- StyleResourceValue(String name) {
- super(name);
- }
-
- StyleResourceValue(String name, String parentStyle) {
- super(name);
- mParentStyle = parentStyle;
- }
-
- public String getParentStyle() {
- return mParentStyle;
- }
-
- public IResourceValue findItem(String name) {
- return mItems.get(name);
- }
-
- public void addItem(IResourceValue value) {
- mItems.put(value.getName(), value);
- }
-
- @Override
- public void replaceWith(ResourceValue value) {
- super.replaceWith(value);
-
- if (value instanceof StyleResourceValue) {
- mItems.clear();
- mItems.putAll(((StyleResourceValue)value).mItems);
- }
- }
-
-}
diff --git a/tools/layoutlib/bridge/tests/data/button.9.png b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/button.9.png
similarity index 100%
rename from tools/layoutlib/bridge/tests/data/button.9.png
rename to tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/button.9.png
diff --git a/tools/layoutlib/bridge/tests/data/layout1.xml b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/layout1.xml
similarity index 100%
rename from tools/layoutlib/bridge/tests/data/layout1.xml
rename to tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/layout1.xml
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index 1adcc17270218..7b55ed3e8aff3 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -68,6 +68,7 @@ public class AsmGenerator {
*
* @param log Output logger.
* @param osDestJar The path of the destination JAR to create.
+ * @param injectClasses The list of class from layoutlib_create to inject in layoutlib.
* @param stubMethods The list of methods to stub out. Each entry must be in the form
* "package.package.OuterClass$InnerClass#MethodName".
* @param renameClasses The list of classes to rename, must be an even list: the binary FQCN
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
new file mode 100644
index 0000000000000..5a13b0be2bb3a
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+public class CreateInfo {
+ /**
+ * The list of class from layoutlib_create to inject in layoutlib.
+ */
+ public final static Class>[] INJECTED_CLASSES = new Class>[] {
+ OverrideMethod.class,
+ MethodListener.class,
+ MethodAdapter.class,
+ CreateInfo.class
+ };
+
+ /**
+ * The list of methods to stub out. Each entry must be in the form
+ * "package.package.OuterClass$InnerClass#MethodName".
+ */
+ public final static String[] OVERRIDDEN_METHODS = new String[] {
+ "android.view.View#isInEditMode",
+ "android.content.res.Resources$Theme#obtainStyledAttributes",
+ };
+
+ /**
+ * The list of classes to rename, must be an even list: the binary FQCN
+ * of class to replace followed by the new FQCN.
+ */
+ public final static String[] RENAMED_CLASSES =
+ new String[] {
+ "android.graphics.Bitmap", "android.graphics._Original_Bitmap",
+ "android.graphics.BitmapShader", "android.graphics._Original_BitmapShader",
+ "android.graphics.Canvas", "android.graphics._Original_Canvas",
+ "android.graphics.ComposeShader", "android.graphics._Original_ComposeShader",
+ "android.graphics.LinearGradient", "android.graphics._Original_LinearGradient",
+ "android.graphics.Matrix", "android.graphics._Original_Matrix",
+ "android.graphics.Paint", "android.graphics._Original_Paint",
+ "android.graphics.Path", "android.graphics._Original_Path",
+ "android.graphics.PorterDuffXfermode", "android.graphics._Original_PorterDuffXfermode",
+ "android.graphics.RadialGradient", "android.graphics._Original_RadialGradient",
+ "android.graphics.Shader", "android.graphics._Original_Shader",
+ "android.graphics.SweepGradient", "android.graphics._Original_SweepGradient",
+ "android.graphics.Typeface", "android.graphics._Original_Typeface",
+ "android.os.ServiceManager", "android.os._Original_ServiceManager",
+ "android.util.FloatMath", "android.util._Original_FloatMath",
+ "android.view.SurfaceView", "android.view._Original_SurfaceView",
+ "android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager",
+ };
+
+ /**
+ * List of classes for which the methods returning them should be deleted.
+ * The array contains a list of null terminated section starting with the name of the class
+ * to rename in which the methods are deleted, followed by a list of return types identifying
+ * the methods to delete.
+ */
+ public final static String[] REMOVED_METHODS =
+ new String[] {
+ "android.graphics.Paint", // class to delete methods from
+ "android.graphics.Paint$Align", // list of type identifying methods to delete
+ "android.graphics.Paint$Style",
+ "android.graphics.Paint$Join",
+ "android.graphics.Paint$Cap",
+ "android.graphics.Paint$FontMetrics",
+ "android.graphics.Paint$FontMetricsInt",
+ null }; // separator, for next class/methods list.
+}
+
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index 47184f10efdc6..303f0974343c2 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -43,44 +43,10 @@ public class Main {
try {
AsmGenerator agen = new AsmGenerator(log, osDestJar[0],
- new Class>[] { // classes to inject in the final JAR
- OverrideMethod.class,
- MethodListener.class,
- MethodAdapter.class
- },
- new String[] { // methods to force override
- "android.view.View#isInEditMode",
- "android.content.res.Resources$Theme#obtainStyledAttributes",
- },
- new String[] { // classes to rename (so that we can replace them in layoutlib)
- // original-platform-class-name ======> renamed-class-name
- "android.graphics.Bitmap", "android.graphics._Original_Bitmap",
- "android.graphics.BitmapShader", "android.graphics._Original_BitmapShader",
- "android.graphics.Canvas", "android.graphics._Original_Canvas",
- "android.graphics.ComposeShader", "android.graphics._Original_ComposeShader",
- "android.graphics.LinearGradient", "android.graphics._Original_LinearGradient",
- "android.graphics.Matrix", "android.graphics._Original_Matrix",
- "android.graphics.Paint", "android.graphics._Original_Paint",
- "android.graphics.Path", "android.graphics._Original_Path",
- "android.graphics.PorterDuffXfermode", "android.graphics._Original_PorterDuffXfermode",
- "android.graphics.RadialGradient", "android.graphics._Original_RadialGradient",
- "android.graphics.Shader", "android.graphics._Original_Shader",
- "android.graphics.SweepGradient", "android.graphics._Original_SweepGradient",
- "android.graphics.Typeface", "android.graphics._Original_Typeface",
- "android.os.ServiceManager", "android.os._Original_ServiceManager",
- "android.util.FloatMath", "android.util._Original_FloatMath",
- "android.view.SurfaceView", "android.view._Original_SurfaceView",
- "android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager",
- },
- new String[] { // methods deleted from their return type.
- "android.graphics.Paint", // class to delete method from
- "android.graphics.Paint$Align", // list of type identifying methods to delete
- "android.graphics.Paint$Style",
- "android.graphics.Paint$Join",
- "android.graphics.Paint$Cap",
- "android.graphics.Paint$FontMetrics",
- "android.graphics.Paint$FontMetricsInt",
- null }
+ CreateInfo.INJECTED_CLASSES,
+ CreateInfo.OVERRIDDEN_METHODS,
+ CreateInfo.RENAMED_CLASSES,
+ CreateInfo.REMOVED_METHODS
);
AsmAnalyzer aa = new AsmAnalyzer(log, osJarPath, agen,