Merge change 25535 into eclair
* changes:
CDMA Check for network duplicate sms
diff --git a/Android.mk b/Android.mk
index 138ff09..4e7b14e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -126,6 +126,8 @@
core/java/android/view/IWindow.aidl \
core/java/android/view/IWindowManager.aidl \
core/java/android/view/IWindowSession.aidl \
+ core/java/android/speech/IRecognitionListener.aidl \
+ core/java/android/speech/IRecognitionService.aidl \
core/java/android/speech/tts/ITts.aidl \
core/java/android/speech/tts/ITtsCallback.aidl \
core/java/com/android/internal/app/IBatteryStats.aidl \
diff --git a/api/current.xml b/api/current.xml
index e438f6e..2c9a087 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -26137,6 +26137,16 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="BluetoothClass.Device"
extends="java.lang.Object"
@@ -27197,6 +27207,16 @@
visibility="public"
>
</field>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ERROR"
type="int"
transient="false"
@@ -27401,6 +27421,87 @@
>
</method>
</class>
+<class name="ParcelUuid"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="ParcelUuid"
+ type="android.bluetooth.ParcelUuid"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uuid" type="java.util.UUID">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="fromString"
+ return="android.bluetooth.ParcelUuid"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uuid" type="java.lang.String">
+</parameter>
+</method>
+<method name="getUuid"
+ return="java.util.UUID"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
</package>
<package name="android.content"
>
@@ -35178,6 +35279,17 @@
visibility="public"
>
</field>
+<field name="ACTION_DOCK_EVENT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.intent.action.DOCK_EVENT""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_EDIT"
type="java.lang.String"
transient="false"
@@ -35893,6 +36005,17 @@
visibility="public"
>
</field>
+<field name="CATEGORY_CAR_DOCK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.intent.category.CAR_DOCK""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="CATEGORY_DEFAULT"
type="java.lang.String"
transient="false"
@@ -35904,6 +36027,17 @@
visibility="public"
>
</field>
+<field name="CATEGORY_DESK_DOCK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.intent.category.DESK_DOCK""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="CATEGORY_DEVELOPMENT_PREFERENCE"
type="java.lang.String"
transient="false"
@@ -36123,6 +36257,50 @@
visibility="public"
>
</field>
+<field name="EXTRA_DOCK_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.intent.extra.DOCK_STATE""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DOCK_STATE_CAR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DOCK_STATE_DESK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DOCK_STATE_UNDOCKED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_DONT_KILL_APP"
type="java.lang.String"
transient="false"
@@ -129286,6 +129464,17 @@
visibility="public"
>
</field>
+<field name="TYPE_TEXT_FLAG_NO_SUGGESTIONS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="524288"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TYPE_TEXT_VARIATION_EMAIL_ADDRESS"
type="int"
transient="false"
diff --git a/cmds/keystore/netkeystore.c b/cmds/keystore/netkeystore.c
index 83c7871..87fdc80 100644
--- a/cmds/keystore/netkeystore.c
+++ b/cmds/keystore/netkeystore.c
@@ -116,10 +116,13 @@
static int is_alnum_string(char *s)
{
+ char *s0 = s;
while (*s != 0) {
- if (!isalnum(*s++)) return 0;
+ if (!isalnum(*s++)) {
+ LOGE("The string '%s' is not an alphanumeric string\n", s0);
+ return 0;
+ }
}
- LOGE("The string %s is not an alphanumeric string\n", s);
return 1;
}
@@ -159,7 +162,9 @@
// no argument
static void do_get_state(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
{
- reply->retcode = get_state();
+ int s = get_state();
+ if (DBG) LOGD("keystore state = %d\n", s);
+ reply->retcode = s;
}
// args of listkeys():
@@ -413,12 +418,10 @@
// read the command, execute and send the result back.
if(read_marshal(s, &cmd)) goto err;
- if (DBG) LOGD("new connection\n");
execute(&cmd, &reply);
write_marshal(s, &reply);
err:
memset(&reply, 0, sizeof(LPC_MARSHAL));
- if (DBG) LOGD("closing connection\n");
close(s);
}
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 73215d3..5397a69 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -61,6 +61,66 @@
decoder->start();
+ if (gReproduceBug == 3) {
+ status_t err;
+ MediaBuffer *buffer;
+ MediaSource::ReadOptions options;
+ int64_t seekTimeUs = -1;
+ for (;;) {
+ err = decoder->read(&buffer, &options);
+ options.clearSeekTo();
+
+ bool shouldSeek = false;
+ if (err != OK) {
+ printf("reached EOF.\n");
+
+ shouldSeek = true;
+ } else {
+ int32_t units, scale;
+ CHECK(buffer->meta_data()->findInt32(kKeyTimeUnits, &units));
+ CHECK(buffer->meta_data()->findInt32(kKeyTimeScale, &scale));
+ int64_t timestamp = ((OMX_TICKS)units * 1000000) / scale;
+
+ bool failed = false;
+ if (seekTimeUs >= 0) {
+ int64_t diff = timestamp - seekTimeUs;
+
+ if (diff > 500000) {
+ printf("ERROR: ");
+ failed = true;
+ }
+ }
+
+ printf("buffer has timestamp %lld us (%.2f secs)\n",
+ timestamp, timestamp / 1E6);
+
+ buffer->release();
+ buffer = NULL;
+
+ if (failed) {
+ break;
+ }
+
+ shouldSeek = ((double)rand() / RAND_MAX) < 0.1;
+ shouldSeek = false;
+ }
+
+ seekTimeUs = -1;
+
+ if (shouldSeek) {
+ seekTimeUs = (rand() * 30E6) / RAND_MAX;
+ options.setSeekTo(seekTimeUs);
+
+ printf("seeking to %lld us (%.2f secs)\n",
+ seekTimeUs, seekTimeUs / 1E6);
+ }
+ }
+
+ decoder->stop();
+
+ return;
+ }
+
int n = 0;
int64_t startTime = getNowUs();
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index c13893a..4217957 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -46,7 +46,6 @@
import android.app.PendingIntent;
import android.app.NotificationManager;
import android.app.Notification;
-import android.app.Activity;
import android.Manifest;
import java.io.FileDescriptor;
@@ -471,6 +470,7 @@
}
private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
+ cancelNotification(getSigninRequiredNotificationId(account));
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
db.beginTransaction();
try {
@@ -523,7 +523,7 @@
checkAuthenticateAccountsPermission(account);
long identityToken = clearCallingIdentity();
try {
- cacheAuthToken(account, authTokenType, authToken);
+ saveAuthTokenToDatabase(account, authTokenType, authToken);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -686,7 +686,8 @@
"the type and name should not be empty");
return;
}
- cacheAuthToken(new Account(name, type), authTokenType, authToken);
+ saveAuthTokenToDatabase(new Account(name, type),
+ authTokenType, authToken);
}
Intent intent = result.getParcelable(Constants.INTENT_KEY);
@@ -714,11 +715,14 @@
Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
0 /* when */);
- final CharSequence subtitleFormatString =
- mContext.getText(R.string.permission_request_notification_subtitle);
+ final String titleAndSubtitle =
+ mContext.getString(R.string.permission_request_notification_with_subtitle,
+ account.name);
+ final int index = titleAndSubtitle.indexOf('\n');
+ final String title = titleAndSubtitle.substring(0, index);
+ final String subtitle = titleAndSubtitle.substring(index + 1);
n.setLatestEventInfo(mContext,
- mContext.getText(R.string.permission_request_notification_title),
- String.format(subtitleFormatString.toString(), account.name),
+ title, subtitle,
PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
.notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
@@ -1001,10 +1005,6 @@
}
}
- private boolean cacheAuthToken(Account account, String authTokenType, String authToken) {
- return saveAuthTokenToDatabase(account, authTokenType, authToken);
- }
-
private long getAccountId(SQLiteDatabase db, Account account) {
Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
"name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 75a90c4..1209d0f 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -739,11 +739,6 @@
return false;
}
- // handle back key to go back to previous searchable, etc.
- if (handleBackKey(keyCode, event)) {
- return true;
- }
-
if (keyCode == KeyEvent.KEYCODE_SEARCH) {
// Consume search key for later use.
return true;
@@ -756,8 +751,8 @@
launchQuerySearch(keyCode, actionKey.getQueryActionMsg());
return true;
}
-
- return false;
+
+ return super.onKeyDown(keyCode, event);
}
@Override
@@ -767,11 +762,6 @@
return false;
}
- // handle back key to go back to previous searchable, etc.
- if (handleBackKey(keyCode, event)) {
- return true;
- }
-
if (keyCode == KeyEvent.KEYCODE_SEARCH && event.isTracking()
&& !event.isCanceled()) {
// If the search key is pressed, toggle between global and in-app search. If we are
@@ -779,8 +769,8 @@
// just don't do anything.
return toggleGlobalSearch();
}
-
- return false;
+
+ return super.onKeyUp(keyCode, event);
}
/**
@@ -1488,6 +1478,13 @@
}
/**
+ * Checks if there are any previous searchable components in the history stack.
+ */
+ private boolean hasPreviousComponent() {
+ return mPreviousComponents != null && !mPreviousComponents.isEmpty();
+ }
+
+ /**
* Saves the previous component that was searched, so that we can go
* back to it.
*/
@@ -1505,14 +1502,10 @@
* no previous component.
*/
private ComponentName popPreviousComponent() {
- if (mPreviousComponents == null) {
+ if (!hasPreviousComponent()) {
return null;
}
- int size = mPreviousComponents.size();
- if (size == 0) {
- return null;
- }
- return mPreviousComponents.remove(size - 1);
+ return mPreviousComponents.remove(mPreviousComponents.size() - 1);
}
/**
@@ -1520,25 +1513,22 @@
*
* @return <code>true</code> if there was a previous component that we could go back to.
*/
- private boolean backToPreviousComponent(boolean doIt) {
+ private boolean backToPreviousComponent() {
ComponentName previous = popPreviousComponent();
if (previous == null) {
return false;
}
-
- if (doIt) {
- if (!show(previous, mAppSearchData, false)) {
- Log.w(LOG_TAG, "Failed to switch to source " + previous);
- return false;
- }
-
- // must touch text to trigger suggestions
- // TODO: should this be the text as it was when the user left
- // the source that we are now going back to?
- String query = mSearchAutoComplete.getText().toString();
- setUserQuery(query);
+
+ if (!show(previous, mAppSearchData, false)) {
+ Log.w(LOG_TAG, "Failed to switch to source " + previous);
+ return false;
}
-
+
+ // must touch text to trigger suggestions
+ // TODO: should this be the text as it was when the user left
+ // the source that we are now going back to?
+ String query = mSearchAutoComplete.getText().toString();
+ setUserQuery(query);
return true;
}
@@ -1763,74 +1753,49 @@
*/
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+ if (DBG) Log.d(LOG_TAG, "onKeyPreIme(" + keyCode + "," + event + ")");
if (mSearchDialog.mSearchable == null) {
return false;
}
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getRepeatCount() == 0) {
- // We release the back key, might we want to do
- // something before the IME?
- if (mSearchDialog.backToPreviousComponent(false)) {
+ if (mSearchDialog.hasPreviousComponent() || isDismissingKeyboardPointless()) {
getKeyDispatcherState().startTracking(event, this);
return true;
}
- if (isInputMethodNotNeeded() ||
- (isEmpty() && getDropDownChildCount() >= getAdapterCount())) {
- getKeyDispatcherState().startTracking(event, this);
- return true;
- }
- return false; // will dismiss soft keyboard if necessary
} else if (event.getAction() == KeyEvent.ACTION_UP
&& event.isTracking() && !event.isCanceled()) {
- if (mSearchDialog.backToPreviousComponent(true)) {
+ if (mSearchDialog.backToPreviousComponent()) {
return true;
- }
- // If the drop-down obscures the keyboard, the user wouldn't see anything
- // happening when pressing back, so we dismiss the entire dialog instead.
- //
- // also: if there is no text entered, we also want to dismiss the whole dialog,
- // not just the soft keyboard. the exception to this is if there are shortcuts
- // that aren't displayed (e.g are being obscured by the soft keyboard); in that
- // case we want to dismiss the soft keyboard so the user can see the rest of the
- // shortcuts.
- if (isInputMethodNotNeeded() ||
- (isEmpty() && getDropDownChildCount() >= getAdapterCount())) {
+ } else if (isDismissingKeyboardPointless()) {
mSearchDialog.cancel();
return true;
}
- return false; // will dismiss soft keyboard if necessary
}
}
return false;
}
+ // If the drop-down obscures the keyboard, or if the drop-down shows all suggestions,
+ // dismissing the keyboard is pointless, so we dismiss the entire dialog instead.
+ private boolean isDismissingKeyboardPointless() {
+ return (isInputMethodNotNeeded() || getDropDownChildCount() >= getAdapterCount());
+ }
+
private int getAdapterCount() {
final ListAdapter adapter = getAdapter();
return adapter == null ? 0 : adapter.getCount();
}
}
-
- protected boolean handleBackKey(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (event.getAction() == KeyEvent.ACTION_DOWN
- && event.getRepeatCount() == 0) {
- // Consume the event, to get an up at which point we execute.
- event.startTracking();
- return true;
- }
- if (event.getAction() == KeyEvent.ACTION_UP && event.isTracking()
- && !event.isCanceled()) {
- if (backToPreviousComponent(true)) {
- return true;
- }
- cancel();
- }
- return true;
+
+ @Override
+ public void onBackPressed() {
+ if (!backToPreviousComponent()) {
+ cancel();
}
- return false;
}
-
+
/**
* Implements OnItemClickListener
*/
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 1fbbf78..6210380 100644
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -72,12 +72,10 @@
return Integer.toHexString(mClass);
}
- /** @hide */
public int describeContents() {
return 0;
}
- /** @hide */
public static final Parcelable.Creator<BluetoothClass> CREATOR =
new Parcelable.Creator<BluetoothClass>() {
public BluetoothClass createFromParcel(Parcel in) {
@@ -88,7 +86,6 @@
}
};
- /** @hide */
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mClass);
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index b1861ac..f81ba73 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -349,12 +349,10 @@
return mAddress;
}
- /** @hide */
public int describeContents() {
return 0;
}
- /** @hide */
public static final Parcelable.Creator<BluetoothDevice> CREATOR =
new Parcelable.Creator<BluetoothDevice>() {
public BluetoothDevice createFromParcel(Parcel in) {
@@ -365,7 +363,6 @@
}
};
- /** @hide */
public void writeToParcel(Parcel out, int flags) {
out.writeString(mAddress);
}
@@ -503,7 +500,7 @@
}
/** @hide */
- public String[] getUuids() {
+ public ParcelUuid[] getUuids() {
try {
return sService.getRemoteUuids(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -511,7 +508,7 @@
}
/** @hide */
- public int getServiceChannel(String uuid) {
+ public int getServiceChannel(ParcelUuid uuid) {
try {
return sService.getRemoteServiceChannel(mAddress, uuid);
} catch (RemoteException e) {Log.e(TAG, "", e);}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index c15bc20..409c744 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -16,10 +16,11 @@
package android.bluetooth;
-import java.util.UUID;
+import java.util.Arrays;
+import java.util.HashSet;
/**
-* Static helper methods and constants to decode the UUID of remote devices.
+* Static helper methods and constants to decode the ParcelUuid of remote devices.
* @hide
*/
public final class BluetoothUuid {
@@ -30,40 +31,99 @@
* The following 128 bit values are calculated as:
* uuid * 2^96 + BASE_UUID
*/
- public static final UUID AudioSink = UUID.fromString("0000110B-0000-1000-8000-00805F9B34FB");
- public static final UUID AudioSource = UUID.fromString("0000110A-0000-1000-8000-00805F9B34FB");
- public static final UUID AdvAudioDist = UUID.fromString("0000110D-0000-1000-8000-00805F9B34FB");
- public static final UUID HSP = UUID.fromString("00001108-0000-1000-8000-00805F9B34FB");
- public static final UUID Handsfree = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
- public static final UUID AvrcpController =
- UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");
- public static final UUID AvrcpTarget = UUID.fromString("0000110C-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid AudioSink =
+ ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid AudioSource =
+ ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid AdvAudioDist =
+ ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid HSP =
+ ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid Handsfree =
+ ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid AvrcpController =
+ ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid AvrcpTarget =
+ ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid ObexObjectPush =
+ ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
- public static boolean isAudioSource(UUID uuid) {
+ public static boolean isAudioSource(ParcelUuid uuid) {
return uuid.equals(AudioSource);
}
- public static boolean isAudioSink(UUID uuid) {
+ public static boolean isAudioSink(ParcelUuid uuid) {
return uuid.equals(AudioSink);
}
- public static boolean isAdvAudioDist(UUID uuid) {
+ public static boolean isAdvAudioDist(ParcelUuid uuid) {
return uuid.equals(AdvAudioDist);
}
- public static boolean isHandsfree(UUID uuid) {
+ public static boolean isHandsfree(ParcelUuid uuid) {
return uuid.equals(Handsfree);
}
- public static boolean isHeadset(UUID uuid) {
+ public static boolean isHeadset(ParcelUuid uuid) {
return uuid.equals(HSP);
}
- public static boolean isAvrcpController(UUID uuid) {
+ public static boolean isAvrcpController(ParcelUuid uuid) {
return uuid.equals(AvrcpController);
}
- public static boolean isAvrcpTarget(UUID uuid) {
+ public static boolean isAvrcpTarget(ParcelUuid uuid) {
return uuid.equals(AvrcpTarget);
}
+
+ /**
+ * Returns true if ParcelUuid is present in uuidArray
+ *
+ * @param uuidArray - Array of ParcelUuids
+ * @param uuid
+ */
+ public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
+ for (ParcelUuid element: uuidArray) {
+ if (element.equals(uuid)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if there any common ParcelUuids in uuidA and uuidB.
+ *
+ * @param uuidA - List of ParcelUuids
+ * @param uuidB - List of ParcelUuids
+ *
+ */
+ public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
+ if (uuidA == null && uuidB == null) return true;
+ if (uuidA == null || uuidB == null) return false;
+
+ HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (Arrays.asList(uuidA));
+ for (ParcelUuid uuid: uuidB) {
+ if (uuidSet.contains(uuid)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if all the ParcelUuids in ParcelUuidB are present in
+ * ParcelUuidA
+ *
+ * @param uuidA - Array of ParcelUuidsA
+ * @param uuidB - Array of ParcelUuidsB
+ *
+ */
+ public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
+ if (uuidA == null && uuidB == null) return true;
+ if (uuidA == null || uuidB == null) return false;
+
+ HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (Arrays.asList(uuidA));
+ for (ParcelUuid uuid: uuidB) {
+ if (!uuidSet.contains(uuid)) return false;
+ }
+ return true;
+ }
+
}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index a11ceac..04c8ec9 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.bluetooth.ParcelUuid;
+
/**
* System private API for talking with the Bluetooth service.
*
@@ -50,8 +52,8 @@
String getRemoteName(in String address);
int getRemoteClass(in String address);
- String[] getRemoteUuids(in String address);
- int getRemoteServiceChannel(in String address, String uuid);
+ ParcelUuid[] getRemoteUuids(in String address);
+ int getRemoteServiceChannel(in String address,in ParcelUuid uuid);
boolean setPin(in String address, in byte[] pin);
boolean setPasskey(in String address, int passkey);
diff --git a/core/java/android/bluetooth/ParcelUuid.aidl b/core/java/android/bluetooth/ParcelUuid.aidl
new file mode 100644
index 0000000..70bcc4b
--- /dev/null
+++ b/core/java/android/bluetooth/ParcelUuid.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.bluetooth;
+
+parcelable ParcelUuid;
diff --git a/core/java/android/bluetooth/ParcelUuid.java b/core/java/android/bluetooth/ParcelUuid.java
new file mode 100644
index 0000000..27166a0
--- /dev/null
+++ b/core/java/android/bluetooth/ParcelUuid.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.UUID;
+
+/**
+ * This class is a Parcelable wrapper around {@link UUID} which is an
+ * immutable representation of a 128-bit universally unique
+ * identifier.
+ */
+public final class ParcelUuid implements Parcelable {
+
+ private final UUID mUuid;
+
+ /**
+ * Constructor creates a ParcelUuid instance from the
+ * given {@link UUID}.
+ *
+ * @param uuid UUID
+ */
+ public ParcelUuid(UUID uuid) {
+ mUuid = uuid;
+ }
+
+ /**
+ * Creates a new ParcelUuid from a string representation of {@link UUID}.
+ *
+ * @param uuid
+ * the UUID string to parse.
+ * @return an ParcelUuid instance.
+ * @throws NullPointerException
+ * if {@code uuid} is {@code null}.
+ * @throws IllegalArgumentException
+ * if {@code uuid} is not formatted correctly.
+ */
+ public static ParcelUuid fromString(String uuid) {
+ return new ParcelUuid(UUID.fromString(uuid));
+ }
+
+ /**
+ * Get the {@link UUID} represented by the ParcelUuid.
+ *
+ * @return UUID contained in the ParcelUuid.
+ */
+ public UUID getUuid() {
+ return mUuid;
+ }
+
+ /**
+ * Returns a string representation of the ParcelUuid
+ * For example: 0000110B-0000-1000-8000-00805F9B34FB will be the return value.
+ *
+ * @return a String instance.
+ */
+ @Override
+ public String toString() {
+ return mUuid.toString();
+ }
+
+
+ @Override
+ public int hashCode() {
+ return mUuid.hashCode();
+ }
+
+ /**
+ * Compares this ParcelUuid to another object for equality. If {@code object}
+ * is not {@code null}, is a ParcelUuid instance, and all bits are equal, then
+ * {@code true} is returned.
+ *
+ * @param object
+ * the {@code Object} to compare to.
+ * @return {@code true} if this ParcelUuid is equal to {@code object}
+ * or {@code false} if not.
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (object == null) {
+ return false;
+ }
+
+ if (this == object) {
+ return true;
+ }
+
+ if (!(object instanceof ParcelUuid)) {
+ return false;
+ }
+
+ ParcelUuid that = (ParcelUuid) object;
+
+ return (this.mUuid.equals(that.mUuid));
+ }
+
+ public static final Parcelable.Creator<ParcelUuid> CREATOR =
+ new Parcelable.Creator<ParcelUuid>() {
+ public ParcelUuid createFromParcel(Parcel source) {
+ long mostSigBits = source.readLong();
+ long leastSigBits = source.readLong();
+ UUID uuid = new UUID(mostSigBits, leastSigBits);
+ return new ParcelUuid(uuid);
+ }
+
+ public ParcelUuid[] newArray(int size) {
+ return new ParcelUuid[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mUuid.getMostSignificantBits());
+ dest.writeLong(mUuid.getLeastSignificantBits());
+ }
+}
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 238792b..60b406d 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -221,26 +221,30 @@
} else if (mType == TYPE_UPDATE) {
numRows = provider.update(mUri, values, mSelection, selectionArgs);
} else if (mType == TYPE_ASSERT) {
- // Build projection map from expected values
- final ArrayList<String> projectionList = new ArrayList<String>();
- for (Map.Entry<String, Object> entry : values.valueSet()) {
- projectionList.add(entry.getKey());
- }
-
// Assert that all rows match expected values
- final String[] projection = projectionList.toArray(new String[projectionList.size()]);
+ String[] projection = null;
+ if (values != null) {
+ // Build projection map from expected values
+ final ArrayList<String> projectionList = new ArrayList<String>();
+ for (Map.Entry<String, Object> entry : values.valueSet()) {
+ projectionList.add(entry.getKey());
+ }
+ projection = projectionList.toArray(new String[projectionList.size()]);
+ }
final Cursor cursor = provider.query(mUri, projection, mSelection, selectionArgs, null);
- numRows = cursor.getCount();
try {
- while (cursor.moveToNext()) {
- for (int i = 0; i < projection.length; i++) {
- final String cursorValue = cursor.getString(i);
- final String expectedValue = values.getAsString(projection[i]);
- if (!TextUtils.equals(cursorValue, expectedValue)) {
- // Throw exception when expected values don't match
- throw new OperationApplicationException("Found value " + cursorValue
- + " when expected " + expectedValue + " for column "
- + projection[i]);
+ numRows = cursor.getCount();
+ if (projection != null) {
+ while (cursor.moveToNext()) {
+ for (int i = 0; i < projection.length; i++) {
+ final String cursorValue = cursor.getString(i);
+ final String expectedValue = values.getAsString(projection[i]);
+ if (!TextUtils.equals(cursorValue, expectedValue)) {
+ // Throw exception when expected values don't match
+ throw new OperationApplicationException("Found value " + cursorValue
+ + " when expected " + expectedValue + " for column "
+ + projection[i]);
+ }
}
}
}
@@ -395,12 +399,19 @@
/** Create a ContentProviderOperation from this {@link Builder}. */
public ContentProviderOperation build() {
- if (mType == TYPE_UPDATE || mType == TYPE_ASSERT) {
+ if (mType == TYPE_UPDATE) {
if ((mValues == null || mValues.size() == 0)
&& (mValuesBackReferences == null || mValuesBackReferences.size() == 0)) {
throw new IllegalArgumentException("Empty values");
}
}
+ if (mType == TYPE_ASSERT) {
+ if ((mValues == null || mValues.size() == 0)
+ && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)
+ && (mExpectedCount == null)) {
+ throw new IllegalArgumentException("Empty values");
+ }
+ }
return new ContentProviderOperation(this);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c053ace..fc977c8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -529,6 +529,8 @@
* <li> {@link #CATEGORY_HOME}
* <li> {@link #CATEGORY_PREFERENCE}
* <li> {@link #CATEGORY_TEST}
+ * <li> {@link #CATEGORY_CAR_DOCK}
+ * <li> {@link #CATEGORY_DESK_DOCK}
* </ul>
*
* <h3>Standard Extra Data</h3>
@@ -1861,12 +1863,29 @@
*/
public static final String CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST =
"android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST";
+ /**
+ * An activity to run when device is inserted into a car dock.
+ * Used with {@link #ACTION_MAIN} to launch an activity.
+ * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK";
+ /**
+ * An activity to run when device is inserted into a car dock.
+ * Used with {@link #ACTION_MAIN} to launch an activity.
+ * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK";
/**
* Broadcast Action: The phone was docked or undocked. Includes the extra
* field {@link #EXTRA_DOCK_STATE}, containing the current dock state.
- * @hide
+ * This is intended for monitoring the current dock state.
+ * To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK}
+ * or {@link #CATEGORY_DESK_DOCK} instead.
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT";
// ---------------------------------------------------------------------
@@ -2005,28 +2024,24 @@
* {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED},
* {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or
* {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}.
- * @hide
*/
public static final String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE";
/**
* Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
* to represent that the phone is not in any dock.
- * @hide
*/
public static final int EXTRA_DOCK_STATE_UNDOCKED = 0;
/**
* Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
* to represent that the phone is in a desk dock.
- * @hide
*/
public static final int EXTRA_DOCK_STATE_DESK = 1;
/**
* Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
* to represent that the phone is in a car dock.
- * @hide
*/
public static final int EXTRA_DOCK_STATE_CAR = 2;
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index d57155c..1de971b 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -506,6 +506,13 @@
* <P>Type: INTEGER (boolean, readonly)</P>
*/
public static final String CAN_INVITE_OTHERS = "canInviteOthers";
+
+ /**
+ * The owner account for this calendar, based on the calendar (foreign
+ * key into the calendars table).
+ * <P>Type: String</P>
+ */
+ public static final String OWNER_ACCOUNT = "ownerAccount";
}
/**
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 667ec5a..d87018d 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -533,7 +533,7 @@
Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
Cursor cursor = cr.query(photoUri, new String[]{Photos.DATA}, null, null, null);
try {
- if (!cursor.moveToNext()) {
+ if (cursor == null || !cursor.moveToNext()) {
return null;
}
byte[] data = cursor.getBlob(0);
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index afa0a7c..6eaf9dd 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1039,6 +1039,7 @@
public static final int TYPE_WORK_MOBILE = 17;
public static final int TYPE_WORK_PAGER = 18;
public static final int TYPE_ASSISTANT = 19;
+ public static final int TYPE_MMS = 20;
/**
* The phone number as the user entered it.
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 9c687e2..be8c777 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -27,6 +27,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothA2dp;
+import android.bluetooth.ParcelUuid;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -42,7 +43,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
-import java.util.UUID;
public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private static final String TAG = "BluetoothA2dpService";
@@ -188,15 +188,9 @@
}
private boolean isSinkDevice(BluetoothDevice device) {
- String uuids[] = mBluetoothService.getRemoteUuids(device.getAddress());
- UUID uuid;
- if (uuids != null) {
- for (String deviceUuid: uuids) {
- uuid = UUID.fromString(deviceUuid);
- if (BluetoothUuid.isAudioSink(uuid)) {
- return true;
- }
- }
+ ParcelUuid[] uuids = mBluetoothService.getRemoteUuids(device.getAddress());
+ if (uuids != null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) {
+ return true;
}
return false;
}
@@ -229,18 +223,14 @@
for (String path: paths) {
String address = mBluetoothService.getAddressFromObjectPath(path);
BluetoothDevice device = mAdapter.getRemoteDevice(address);
- String []uuids = mBluetoothService.getRemoteUuids(address);
- if (uuids != null)
- for (String uuid: uuids) {
- UUID remoteUuid = UUID.fromString(uuid);
- if (BluetoothUuid.isAudioSink(remoteUuid) ||
- BluetoothUuid.isAudioSource(remoteUuid) ||
- BluetoothUuid.isAdvAudioDist(remoteUuid)) {
- addAudioSink(device);
- break;
- }
+ ParcelUuid[] remoteUuids = mBluetoothService.getRemoteUuids(address);
+ if (remoteUuids != null)
+ if (BluetoothUuid.containsAnyUuid(remoteUuids,
+ new ParcelUuid[] {BluetoothUuid.AudioSink,
+ BluetoothUuid.AdvAudioDist})) {
+ addAudioSink(device);
}
- }
+ }
}
mAudioManager.setParameters(BLUETOOTH_ENABLED+"=true");
}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 1ed5c49..ba53307 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -21,6 +21,7 @@
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothUuid;
+import android.bluetooth.ParcelUuid;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
@@ -28,7 +29,6 @@
import android.util.Log;
import java.util.HashMap;
-import java.util.UUID;
/**
* TODO: Move this to
@@ -501,7 +501,7 @@
}
boolean authorized = false;
- UUID uuid = UUID.fromString(deviceUuid);
+ ParcelUuid uuid = ParcelUuid.fromString(deviceUuid);
// Bluez sends the UUID of the local service being accessed, _not_ the
// remote service
if (mBluetoothService.isEnabled() &&
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index de0cad7..c0e4f34 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -24,11 +24,12 @@
package android.server;
-import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.IBluetooth;
+import android.bluetooth.ParcelUuid;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -51,7 +52,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
public class BluetoothService extends IBluetooth.Stub {
@@ -967,22 +967,26 @@
/**
- * Gets the remote features encoded as bit mask.
+ * Gets the UUIDs supported by the remote device
*
- * Note: This method may be obsoleted soon.
- *
- * @return String array of 128bit UUIDs
+ * @return array of 128bit ParcelUuids
*/
- public synchronized String[] getRemoteUuids(String address) {
+ public synchronized ParcelUuid[] getRemoteUuids(String address) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
return null;
}
String value = getRemoteDeviceProperty(address, "UUIDs");
- String[] uuids = null;
+ if (value == null) return null;
+
+ String[] uuidStrings = null;
// The UUIDs are stored as a "," separated string.
- if (value != null)
- uuids = value.split(",");
+ uuidStrings = value.split(",");
+ ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
+
+ for (int i = 0; i < uuidStrings.length; i++) {
+ uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
+ }
return uuids;
}
@@ -990,16 +994,17 @@
* Gets the rfcomm channel associated with the UUID.
*
* @param address Address of the remote device
- * @param uuid UUID of the service attribute
+ * @param uuid ParcelUuid of the service attribute
*
* @return rfcomm channel associated with the service attribute
*/
- public int getRemoteServiceChannel(String address, String uuid) {
+ public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
return BluetoothDevice.ERROR;
}
- return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid, 0x0004);
+ return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid.toString(),
+ 0x0004);
}
public synchronized boolean setPin(String address, byte[] pin) {
@@ -1148,11 +1153,11 @@
mBondState.getAttempt(address),
getRemoteName(address));
if (bondState == BluetoothDevice.BOND_BONDED) {
- String[] uuids = getRemoteUuids(address);
+ ParcelUuid[] uuids = getRemoteUuids(address);
if (uuids == null) {
pw.printf("\tuuids = null\n");
} else {
- for (String uuid : uuids) {
+ for (ParcelUuid uuid : uuids) {
pw.printf("\t" + uuid + "\n");
}
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index cd5cf10..da8d62c0 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -321,7 +321,7 @@
* Called as the user performs touch-screen interaction with the
* window that is currently showing this wallpaper. Note that the
* events you receive here are driven by the actual application the
- * user is interacting with, so if it is slow you will get viewer
+ * user is interacting with, so if it is slow you will get fewer
* move events.
*/
public void onTouchEvent(MotionEvent event) {
diff --git a/core/java/android/speech/IRecognitionListener.aidl b/core/java/android/speech/IRecognitionListener.aidl
new file mode 100644
index 0000000..2da2258
--- /dev/null
+++ b/core/java/android/speech/IRecognitionListener.aidl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.os.Bundle;
+import android.speech.RecognitionResult;
+
+/**
+ * Listener for speech recognition events, used with RecognitionService.
+ * This gives you both the final recognition results, as well as various
+ * intermediate events that can be used to show visual feedback to the user.
+ * {@hide}
+ */
+interface IRecognitionListener {
+ /** Called when the endpointer is ready for the user to start speaking. */
+ void onReadyForSpeech(in Bundle noiseParams);
+
+ /** The user has started to speak. */
+ void onBeginningOfSpeech();
+
+ /** The sound level in the audio stream has changed. */
+ void onRmsChanged(in float rmsdB);
+
+ /**
+ * More sound has been received. Buffer is a byte buffer containing
+ * a sequence of 16-bit shorts.
+ */
+ void onBufferReceived(in byte[] buffer);
+
+ /** Called after the user stops speaking. */
+ void onEndOfSpeech();
+
+ /**
+ * A network or recognition error occurred. The code is defined in
+ * {@link android.speech.RecognitionResult}
+ */
+ void onError(in int error);
+
+ /**
+ * Called when recognition results are ready.
+ * @param results: an ordered list of the most likely results (N-best list).
+ * @param key: a key associated with the results. The same results can
+ * be retrieved asynchronously later using the key, if available.
+ */
+ void onResults(in List<RecognitionResult> results, long key);
+}
diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl
new file mode 100644
index 0000000..a18c380
--- /dev/null
+++ b/core/java/android/speech/IRecognitionService.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.content.Intent;
+import android.speech.IRecognitionListener;
+import android.speech.RecognitionResult;
+
+// A Service interface to speech recognition. Call startListening when
+// you want to begin capturing audio; RecognitionService will automatically
+// determine when the user has finished speaking, stream the audio to the
+// recognition servers, and notify you when results are ready.
+/** {@hide} */
+interface IRecognitionService {
+ // Start listening for speech. Can only call this from one thread at once.
+ // see RecognizerIntent.java for constants used to specify the intent.
+ void startListening(in Intent recognizerIntent,
+ in IRecognitionListener listener);
+
+ List<RecognitionResult> getRecognitionResults(in long key);
+
+ void cancel();
+}
diff --git a/core/java/android/speech/RecognitionResult.aidl b/core/java/android/speech/RecognitionResult.aidl
new file mode 100644
index 0000000..59e53ab
--- /dev/null
+++ b/core/java/android/speech/RecognitionResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+parcelable RecognitionResult;
diff --git a/core/java/android/speech/RecognitionResult.java b/core/java/android/speech/RecognitionResult.java
new file mode 100644
index 0000000..95715ee
--- /dev/null
+++ b/core/java/android/speech/RecognitionResult.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * RecognitionResult is a passive object that stores a single recognized query
+ * and its search result.
+ *
+ * TODO: Revisit and improve this class, reconciling the different types of actions and
+ * the different ways they are represented. Maybe we should have a separate result object
+ * for each type, and put them (type/value) in bundle?
+ * {@hide}
+ */
+public class RecognitionResult implements Parcelable {
+ /**
+ * Status of the recognize request.
+ */
+ public static final int NETWORK_TIMEOUT = 1; // Network operation timed out.
+
+ public static final int NETWORK_ERROR = 2; // Other network related errors.
+
+ public static final int AUDIO_ERROR = 3; // Audio recording error.
+
+ public static final int SERVER_ERROR = 4; // Server sends error status.
+
+ public static final int CLIENT_ERROR = 5; // Other client side errors.
+
+ public static final int SPEECH_TIMEOUT = 6; // No speech input
+
+ public static final int NO_MATCH = 7; // No recognition result matched.
+
+ public static final int SERVICE_BUSY = 8; // RecognitionService busy.
+
+ /**
+ * Type of the recognition results.
+ */
+ public static final int RAW_RECOGNITION_RESULT = 0;
+
+ public static final int WEB_SEARCH_RESULT = 1;
+
+ public static final int CONTACT_RESULT = 2;
+
+ public static final int ACTION_RESULT = 3;
+
+ /**
+ * A factory method to create a raw RecognitionResult
+ *
+ * @param sentence the recognized text.
+ */
+ public static RecognitionResult newRawRecognitionResult(String sentence) {
+ return new RecognitionResult(RAW_RECOGNITION_RESULT, sentence, null, null);
+ }
+
+ /**
+ * A factory method to create a RecognitionResult for contacts.
+ *
+ * @param contact the contact name.
+ * @param phoneType the phone type.
+ * @param callAction whether this result included a command to "call", or
+ * just the contact name.
+ */
+ public static RecognitionResult newContactResult(String contact, int phoneType,
+ boolean callAction) {
+ return new RecognitionResult(CONTACT_RESULT, contact, phoneType, callAction);
+ }
+
+ /**
+ * A factory method to create a RecognitionResult for a web search query.
+ *
+ * @param query the query string.
+ * @param html the html page of the search result.
+ * @param url the url that performs the search with the query.
+ */
+ public static RecognitionResult newWebResult(String query, String html, String url) {
+ return new RecognitionResult(WEB_SEARCH_RESULT, query, html, url);
+ }
+
+ /**
+ * A factory method to create a RecognitionResult for an action.
+ *
+ * @param action the action type
+ * @param query the query string associated with that action.
+ */
+ public static RecognitionResult newActionResult(int action, String query) {
+ return new RecognitionResult(ACTION_RESULT, action, query);
+ }
+
+ public static final Parcelable.Creator<RecognitionResult> CREATOR =
+ new Parcelable.Creator<RecognitionResult>() {
+
+ public RecognitionResult createFromParcel(Parcel in) {
+ return new RecognitionResult(in);
+ }
+
+ public RecognitionResult[] newArray(int size) {
+ return new RecognitionResult[size];
+ }
+ };
+
+ /**
+ * Result type.
+ */
+ public final int mResultType;
+
+ /**
+ * The recognized string when mResultType is WEB_SEARCH_RESULT. The name of
+ * the contact when mResultType is CONTACT_RESULT. The relevant query when
+ * mResultType is ACTION_RESULT.
+ */
+ public final String mText;
+
+ /**
+ * The HTML result page for the query. If this is null, then the application
+ * must use the url field to get the HTML result page.
+ */
+ public final String mHtml;
+
+ /**
+ * The url to get the result page for the query string. The application must
+ * use this url instead of performing the search with the query.
+ */
+ public final String mUrl;
+
+ /**
+ * Phone number type. This is valid only when mResultType == CONTACT_RESULT.
+ */
+ public final int mPhoneType;
+
+ /**
+ * Action type. This is valid only when mResultType == ACTION_RESULT.
+ */
+ public final int mAction;
+
+ /**
+ * Whether a contact recognition result included a command to "call". This
+ * is valid only when mResultType == CONTACT_RESULT.
+ */
+ public final boolean mCallAction;
+
+ private RecognitionResult(int type, int action, String query) {
+ mResultType = type;
+ mAction = action;
+ mText = query;
+ mHtml = null;
+ mUrl = null;
+ mPhoneType = -1;
+ mCallAction = false;
+ }
+
+ private RecognitionResult(int type, String query, String html, String url) {
+ mResultType = type;
+ mText = query;
+ mHtml = html;
+ mUrl = url;
+ mPhoneType = -1;
+ mAction = -1;
+ mCallAction = false;
+ }
+
+ private RecognitionResult(int type, String query, int phoneType, boolean callAction) {
+ mResultType = type;
+ mText = query;
+ mPhoneType = phoneType;
+ mHtml = null;
+ mUrl = null;
+ mAction = -1;
+ mCallAction = callAction;
+ }
+
+ private RecognitionResult(Parcel in) {
+ mResultType = in.readInt();
+ mText = in.readString();
+ mHtml = in.readString();
+ mUrl = in.readString();
+ mPhoneType = in.readInt();
+ mAction = in.readInt();
+ mCallAction = (in.readInt() == 1);
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mResultType);
+ out.writeString(mText);
+ out.writeString(mHtml);
+ out.writeString(mUrl);
+ out.writeInt(mPhoneType);
+ out.writeInt(mAction);
+ out.writeInt(mCallAction ? 1 : 0);
+ }
+
+ @Override
+ public String toString() {
+ String resultType[] = {
+ "RAW", "WEB", "CONTACT", "ACTION"
+ };
+ return "[type=" + resultType[mResultType] + ", text=" + mText + ", mUrl=" + mUrl
+ + ", html=" + mHtml + ", mAction=" + mAction + ", mCallAction=" + mCallAction + "]";
+ }
+
+ public int describeContents() {
+ // no special description
+ return 0;
+ }
+}
diff --git a/core/java/android/speech/RecognitionServiceUtil.java b/core/java/android/speech/RecognitionServiceUtil.java
new file mode 100644
index 0000000..4207543
--- /dev/null
+++ b/core/java/android/speech/RecognitionServiceUtil.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.speech.RecognitionResult;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Utils for Google's network-based speech recognizer, which lets you perform
+ * speech-to-text translation through RecognitionService. IRecognitionService
+ * and IRecognitionListener are the core interfaces; you begin recognition
+ * through IRecognitionService and subscribe to callbacks about when the user
+ * stopped speaking, results come in, errors, etc. through IRecognitionListener.
+ * RecognitionServiceUtil includes default IRecognitionListener and
+ * ServiceConnection implementations to reduce the amount of boilerplate.
+ *
+ * The Service provides no user interface. See RecognitionActivity if you
+ * want the standard voice search UI.
+ *
+ * Below is a small skeleton of how to use the recognizer:
+ *
+ * ServiceConnection conn = new RecognitionServiceUtil.Connection();
+ * mContext.bindService(RecognitionServiceUtil.sDefaultIntent,
+ * conn, Context.BIND_AUTO_CREATE);
+ * IRecognitionListener listener = new RecognitionServiceWrapper.NullListener() {
+ * public void onResults(List<String> results) {
+ * // Do something with recognition transcripts
+ * }
+ * }
+ *
+ * // Must wait for conn.mService to be populated, then call below
+ * conn.mService.startListening(null, listener);
+ *
+ * {@hide}
+ */
+public class RecognitionServiceUtil {
+ public static final Intent sDefaultIntent = new Intent(
+ RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
+
+ // Recognize request parameters
+ public static final String USE_LOCATION = "useLocation";
+ public static final String CONTACT_AUTH_TOKEN = "contactAuthToken";
+
+ // Bundles
+ public static final String NOISE_LEVEL = "NoiseLevel";
+ public static final String SIGNAL_NOISE_RATIO = "SignalNoiseRatio";
+
+ private RecognitionServiceUtil() {}
+
+ /**
+ * IRecognitionListener which does nothing in response to recognition
+ * callbacks. You can subclass from this and override only the methods
+ * whose events you want to respond to.
+ */
+ public static class NullListener extends IRecognitionListener.Stub {
+ public void onReadyForSpeech(Bundle bundle) {}
+ public void onBeginningOfSpeech() {}
+ public void onRmsChanged(float rmsdB) {}
+ public void onBufferReceived(byte[] buf) {}
+ public void onEndOfSpeech() {}
+ public void onError(int error) {}
+ public void onResults(List<RecognitionResult> results, long key) {}
+ }
+
+ /**
+ * Basic ServiceConnection which just records mService variable.
+ */
+ public static class Connection implements ServiceConnection {
+ public IRecognitionService mService;
+
+ public synchronized void onServiceConnected(ComponentName name, IBinder service) {
+ mService = IRecognitionService.Stub.asInterface(service);
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+ }
+ }
+}
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index d50684a..14b8308 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -128,6 +128,15 @@
*/
public static final int TYPE_TEXT_FLAG_IME_MULTI_LINE = 0x00040000;
+ /**
+ * Flag for {@link #TYPE_CLASS_TEXT}: the input method does not need to
+ * display any dictionary-based candidates. This is useful for text views that
+ * do not contain words from the language and do not benefit from any
+ * dictionary-based completions or corrections. It overrides the
+ * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} value when set.
+ */
+ public static final int TYPE_TEXT_FLAG_NO_SUGGESTIONS = 0x00080000;
+
// ----------------------------------------------------------------------
/**
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 38881d3..f736f85 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -431,6 +431,7 @@
PICKER_SETS.put('z', "\u017A\u017C\u017E");
PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT,
"\u2026\u00A5\u2022\u00AE\u00A9\u00B1[]{}\\");
+ PICKER_SETS.put('/', "\\");
// From packages/inputmethods/LatinIME/res/xml/kbd_symbols.xml
diff --git a/core/java/android/text/util/Rfc822InputFilter.java b/core/java/android/text/util/Rfc822InputFilter.java
new file mode 100644
index 0000000..8c8b7fc
--- /dev/null
+++ b/core/java/android/text/util/Rfc822InputFilter.java
@@ -0,0 +1,58 @@
+package android.text.util;
+
+import android.text.InputFilter;
+import android.text.Spanned;
+import android.text.SpannableStringBuilder;
+
+/**
+ * Implements special address cleanup rules:
+ * The first space key entry following an "@" symbol that is followed by any combination
+ * of letters and symbols, including one+ dots and zero commas, should insert an extra
+ * comma (followed by the space).
+ *
+ * @hide
+ */
+public class Rfc822InputFilter implements InputFilter {
+
+ public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
+ int dstart, int dend) {
+
+ // quick check - did they enter a single space?
+ if (end-start != 1 || source.charAt(start) != ' ') {
+ return null;
+ }
+
+ // determine if the characters before the new space fit the pattern
+ // follow backwards and see if we find a comma, dot, or @
+ int scanBack = dstart;
+ boolean dotFound = false;
+ while (scanBack > 0) {
+ char c = dest.charAt(--scanBack);
+ switch (c) {
+ case '.':
+ dotFound = true; // one or more dots are req'd
+ break;
+ case ',':
+ return null;
+ case '@':
+ if (!dotFound) {
+ return null;
+ }
+ // we have found a comma-insert case. now just do it
+ // in the least expensive way we can.
+ if (source instanceof Spanned) {
+ SpannableStringBuilder sb = new SpannableStringBuilder(",");
+ sb.append(source);
+ return sb;
+ } else {
+ return ", ";
+ }
+ default:
+ // just keep going
+ }
+ }
+
+ // no termination cases were found, so don't edit the input
+ return null;
+ }
+}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 94acd3f..e5985c1 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -458,11 +458,12 @@
public final View createView(String name, String prefix, AttributeSet attrs)
throws ClassNotFoundException, InflateException {
Constructor constructor = sConstructorMap.get(name);
+ Class clazz = null;
try {
if (constructor == null) {
// Class not found in the cache, see if it's real, and try to add it
- Class clazz = mContext.getClassLoader().loadClass(
+ clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name);
if (mFilter != null && clazz != null) {
@@ -480,7 +481,7 @@
Boolean allowedState = mFilterMap.get(name);
if (allowedState == null) {
// New class -- remember whether it is allowed
- Class clazz = mContext.getClassLoader().loadClass(
+ clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name);
boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
@@ -511,7 +512,7 @@
} catch (Exception e) {
InflateException ie = new InflateException(attrs.getPositionDescription()
+ ": Error inflating class "
- + (constructor == null ? "<unknown>" : constructor.getClass().getName()));
+ + (clazz == null ? "<unknown>" : clazz.getName()));
ie.initCause(e);
throw ie;
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index c40107b..bd38b2d 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -361,8 +361,6 @@
public final int OFF_BECAUSE_OF_USER = 1;
/** Screen turned off because of timeout */
public final int OFF_BECAUSE_OF_TIMEOUT = 2;
- /** Screen turned off because of proximity sensor */
- public final int OFF_BECAUSE_OF_PROXIMITY_SENSOR = 3;
/**
* Magic constant to {@link IWindowManager#setRotation} to not actually
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 5a164f8..c10355c 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -17,8 +17,18 @@
package android.webkit;
import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.net.http.EventHandler;
+import android.net.http.Headers;
+import android.net.http.RequestHandle;
+import android.net.http.RequestQueue;
+import android.net.http.SslCertificate;
+import android.net.http.SslError;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -30,182 +40,389 @@
import android.view.ViewGroup;
import android.webkit.ViewManager.ChildView;
import android.widget.AbsoluteLayout;
+import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.VideoView;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.util.HashMap;
+import java.util.Map;
/**
* <p>Proxy for HTML5 video views.
*/
-class HTML5VideoViewProxy extends Handler {
+class HTML5VideoViewProxy extends Handler
+ implements MediaPlayer.OnPreparedListener,
+ MediaPlayer.OnCompletionListener {
// Logging tag.
private static final String LOGTAG = "HTML5VideoViewProxy";
// Message Ids for WebCore thread -> UI thread communication.
private static final int INIT = 100;
private static final int PLAY = 101;
+ private static final int SET_POSTER = 102;
+ private static final int SEEK = 103;
+ private static final int PAUSE = 104;
+ // Message Ids to be handled on the WebCore thread
+ private static final int PREPARED = 200;
+ private static final int ENDED = 201;
+
+ // The C++ MediaPlayerPrivateAndroid object.
+ int mNativePointer;
+ // The handler for WebCore thread messages;
+ private Handler mWebCoreHandler;
// The WebView instance that created this view.
private WebView mWebView;
// The ChildView instance used by the ViewManager.
private ChildView mChildView;
- // The VideoView instance. Note that we could
- // also access this via mChildView.mView but it would
- // always require cast, so it is more convenient to store
- // it here as well.
- private HTML5VideoView mVideoView;
+ // The poster image to be shown when the video is not playing.
+ private ImageView mPosterView;
+ // The poster downloader.
+ private PosterDownloader mPosterDownloader;
+ // The seek position.
+ private int mSeekPosition;
+ // A helper class to control the playback. This executes on the UI thread!
+ private static final class VideoPlayer {
+ // The proxy that is currently playing (if any).
+ private static HTML5VideoViewProxy mCurrentProxy;
+ // The VideoView instance. This is a singleton for now, at least until
+ // http://b/issue?id=1973663 is fixed.
+ private static VideoView mVideoView;
- // A VideoView subclass that responds to double-tap
- // events by going fullscreen.
- class HTML5VideoView extends VideoView {
- // Used to save the layout parameters if the view
- // is changed to fullscreen.
- private AbsoluteLayout.LayoutParams mEmbeddedLayoutParams;
- // Flag that denotes whether the view is fullscreen or not.
- private boolean mIsFullscreen;
- // Used to save the current playback position when
- // transitioning to/from fullscreen.
- private int mPlaybackPosition;
- // The callback object passed to the host application. This callback
- // is invoked when the host application dismisses our VideoView
- // (e.g. the user presses the back key).
- private WebChromeClient.CustomViewCallback mCallback =
- new WebChromeClient.CustomViewCallback() {
- public void onCustomViewHidden() {
- playEmbedded();
- }
- };
+ private static final WebChromeClient.CustomViewCallback mCallback =
+ new WebChromeClient.CustomViewCallback() {
+ public void onCustomViewHidden() {
+ // At this point the videoview is pretty much destroyed.
+ // It listens to SurfaceHolder.Callback.SurfaceDestroyed event
+ // which happens when the video view is detached from its parent
+ // view. This happens in the WebChromeClient before this method
+ // is invoked.
+ mCurrentProxy.playbackEnded();
+ mCurrentProxy = null;
+ mVideoView = null;
+ }
+ };
- // The OnPreparedListener, used to automatically resume
- // playback when transitioning to/from fullscreen.
- private MediaPlayer.OnPreparedListener mPreparedListener =
- new MediaPlayer.OnPreparedListener() {
- public void onPrepared(MediaPlayer mp) {
- resumePlayback();
- }
- };
-
- HTML5VideoView(Context context) {
- super(context);
- }
-
- void savePlaybackPosition() {
- if (isPlaying()) {
- mPlaybackPosition = getCurrentPosition();
- }
- }
-
- void resumePlayback() {
- seekTo(mPlaybackPosition);
- start();
- setOnPreparedListener(null);
- }
-
- void playEmbedded() {
- // Attach to the WebView.
- mChildView.attachViewOnUIThread(mEmbeddedLayoutParams);
- // Make sure we're visible
- setVisibility(View.VISIBLE);
- // Set the onPrepared listener so we start
- // playing when the video view is reattached
- // and its surface is recreated.
- setOnPreparedListener(mPreparedListener);
- mIsFullscreen = false;
- }
-
- void playFullScreen() {
- WebChromeClient client = mWebView.getWebChromeClient();
- if (client == null) {
+ public static void play(String url, int time, HTML5VideoViewProxy proxy,
+ WebChromeClient client) {
+ if (mCurrentProxy != null) {
+ // Some other video is already playing. Notify the caller that its playback ended.
+ proxy.playbackEnded();
return;
}
- // Save the current layout params.
- mEmbeddedLayoutParams =
- (AbsoluteLayout.LayoutParams) getLayoutParams();
- // Detach from the WebView.
- mChildView.removeViewOnUIThread();
- // Attach to the browser UI.
- client.onShowCustomView(this, mCallback);
- // Set the onPrepared listener so we start
- // playing when after the video view is reattached
- // and its surface is recreated.
- setOnPreparedListener(mPreparedListener);
- mIsFullscreen = true;
+ mCurrentProxy = proxy;
+ mVideoView = new VideoView(proxy.getContext());
+ mVideoView.setWillNotDraw(false);
+ mVideoView.setMediaController(new MediaController(proxy.getContext()));
+ mVideoView.setVideoURI(Uri.parse(url));
+ mVideoView.setOnCompletionListener(proxy);
+ mVideoView.setOnPreparedListener(proxy);
+ mVideoView.seekTo(time);
+ mVideoView.start();
+ client.onShowCustomView(mVideoView, mCallback);
}
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- // TODO: implement properly (i.e. detect double tap)
- if (mIsFullscreen || !isPlaying()) {
- return super.onTouchEvent(ev);
+ public static void seek(int time, HTML5VideoViewProxy proxy) {
+ if (mCurrentProxy == proxy && time >= 0 && mVideoView != null) {
+ mVideoView.seekTo(time);
}
- playFullScreen();
- return true;
}
- @Override
- public void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- savePlaybackPosition();
+ public static void pause(HTML5VideoViewProxy proxy) {
+ if (mCurrentProxy == proxy && mVideoView != null) {
+ mVideoView.pause();
+ }
+ }
+ }
+
+ // A bunch event listeners for our VideoView
+ // MediaPlayer.OnPreparedListener
+ public void onPrepared(MediaPlayer mp) {
+ Message msg = Message.obtain(mWebCoreHandler, PREPARED);
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("dur", new Integer(mp.getDuration()));
+ map.put("width", new Integer(mp.getVideoWidth()));
+ map.put("height", new Integer(mp.getVideoHeight()));
+ msg.obj = map;
+ mWebCoreHandler.sendMessage(msg);
+ }
+
+ // MediaPlayer.OnCompletionListener;
+ public void onCompletion(MediaPlayer mp) {
+ playbackEnded();
+ }
+
+ public void playbackEnded() {
+ Message msg = Message.obtain(mWebCoreHandler, ENDED);
+ mWebCoreHandler.sendMessage(msg);
+ }
+
+ // Handler for the messages from WebCore thread to the UI thread.
+ @Override
+ public void handleMessage(Message msg) {
+ // This executes on the UI thread.
+ switch (msg.what) {
+ case INIT: {
+ mPosterView = new ImageView(mWebView.getContext());
+ mChildView.mView = mPosterView;
+ break;
+ }
+ case PLAY: {
+ String url = (String) msg.obj;
+ WebChromeClient client = mWebView.getWebChromeClient();
+ if (client != null) {
+ VideoPlayer.play(url, mSeekPosition, this, client);
+ }
+ break;
+ }
+ case SET_POSTER: {
+ Bitmap poster = (Bitmap) msg.obj;
+ mPosterView.setImageBitmap(poster);
+ break;
+ }
+ case SEEK: {
+ Integer time = (Integer) msg.obj;
+ mSeekPosition = time;
+ VideoPlayer.seek(mSeekPosition, this);
+ break;
+ }
+ case PAUSE: {
+ VideoPlayer.pause(this);
+ break;
+ }
+ }
+ }
+
+ // Everything below this comment executes on the WebCore thread, except for
+ // the EventHandler methods, which are called on the network thread.
+
+ // A helper class that knows how to download posters
+ private static final class PosterDownloader implements EventHandler {
+ // The request queue. This is static as we have one queue for all posters.
+ private static RequestQueue mRequestQueue;
+ private static int mQueueRefCount = 0;
+ // The poster URL
+ private String mUrl;
+ // The proxy we're doing this for.
+ private final HTML5VideoViewProxy mProxy;
+ // The poster bytes. We only touch this on the network thread.
+ private ByteArrayOutputStream mPosterBytes;
+ // The request handle. We only touch this on the WebCore thread.
+ private RequestHandle mRequestHandle;
+ // The response status code.
+ private int mStatusCode;
+ // The response headers.
+ private Headers mHeaders;
+ // The handler to handle messages on the WebCore thread.
+ private Handler mHandler;
+
+ public PosterDownloader(String url, HTML5VideoViewProxy proxy) {
+ mUrl = url;
+ mProxy = proxy;
+ mHandler = new Handler();
+ }
+ // Start the download. Called on WebCore thread.
+ public void start() {
+ retainQueue();
+ mRequestHandle = mRequestQueue.queueRequest(mUrl, "GET", null, this, null, 0);
+ }
+ // Cancel the download if active and release the queue. Called on WebCore thread.
+ public void cancelAndReleaseQueue() {
+ if (mRequestHandle != null) {
+ mRequestHandle.cancel();
+ mRequestHandle = null;
+ }
+ releaseQueue();
+ }
+ // EventHandler methods. Executed on the network thread.
+ public void status(int major_version,
+ int minor_version,
+ int code,
+ String reason_phrase) {
+ mStatusCode = code;
+ }
+
+ public void headers(Headers headers) {
+ mHeaders = headers;
+ }
+
+ public void data(byte[] data, int len) {
+ if (mPosterBytes == null) {
+ mPosterBytes = new ByteArrayOutputStream();
+ }
+ mPosterBytes.write(data, 0, len);
+ }
+
+ public void endData() {
+ if (mStatusCode == 200) {
+ if (mPosterBytes.size() > 0) {
+ Bitmap poster = BitmapFactory.decodeByteArray(
+ mPosterBytes.toByteArray(), 0, mPosterBytes.size());
+ if (poster != null) {
+ mProxy.doSetPoster(poster);
+ }
+ }
+ cleanup();
+ } else if (mStatusCode >= 300 && mStatusCode < 400) {
+ // We have a redirect.
+ mUrl = mHeaders.getLocation();
+ if (mUrl != null) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ if (mRequestHandle != null) {
+ mRequestHandle.setupRedirect(mUrl, mStatusCode,
+ new HashMap<String, String>());
+ }
+ }
+ });
+ }
+ }
+ }
+
+ public void certificate(SslCertificate certificate) {
+ // Don't care.
+ }
+
+ public void error(int id, String description) {
+ cleanup();
+ }
+
+ public boolean handleSslErrorRequest(SslError error) {
+ // Don't care. If this happens, data() will never be called so
+ // mPosterBytes will never be created, so no need to call cleanup.
+ return false;
+ }
+ // Tears down the poster bytes stream. Called on network thread.
+ private void cleanup() {
+ if (mPosterBytes != null) {
+ try {
+ mPosterBytes.close();
+ } catch (IOException ignored) {
+ // Ignored.
+ } finally {
+ mPosterBytes = null;
+ }
+ }
+ }
+
+ // Queue management methods. Called on WebCore thread.
+ private void retainQueue() {
+ if (mRequestQueue == null) {
+ mRequestQueue = new RequestQueue(mProxy.getContext());
+ }
+ mQueueRefCount++;
+ }
+
+ private void releaseQueue() {
+ if (mQueueRefCount == 0) {
+ return;
+ }
+ if (--mQueueRefCount == 0) {
+ mRequestQueue.shutdown();
+ mRequestQueue = null;
+ }
}
}
/**
* Private constructor.
- * @param context is the application context.
+ * @param webView is the WebView that hosts the video.
+ * @param nativePtr is the C++ pointer to the MediaPlayerPrivate object.
*/
- private HTML5VideoViewProxy(WebView webView) {
+ private HTML5VideoViewProxy(WebView webView, int nativePtr) {
// This handler is for the main (UI) thread.
super(Looper.getMainLooper());
// Save the WebView object.
mWebView = webView;
+ // Save the native ptr
+ mNativePointer = nativePtr;
+ // create the message handler for this thread
+ createWebCoreHandler();
}
- @Override
- public void handleMessage(Message msg) {
- // This executes on the UI thread.
- switch (msg.what) {
- case INIT:
- // Create the video view and set a default controller.
- mVideoView = new HTML5VideoView(mWebView.getContext());
- // This is needed because otherwise there will be a black square
- // stuck on the screen.
- mVideoView.setWillNotDraw(false);
- mVideoView.setMediaController(new MediaController(mWebView.getContext()));
- mChildView.mView = mVideoView;
- break;
- case PLAY:
- if (mVideoView == null) {
- return;
+ private void createWebCoreHandler() {
+ mWebCoreHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case PREPARED: {
+ Map<String, Object> map = (Map<String, Object>) msg.obj;
+ Integer duration = (Integer) map.get("dur");
+ Integer width = (Integer) map.get("width");
+ Integer height = (Integer) map.get("height");
+ nativeOnPrepared(duration.intValue(), width.intValue(),
+ height.intValue(), mNativePointer);
+ break;
+ }
+ case ENDED:
+ nativeOnEnded(mNativePointer);
+ break;
}
- HashMap<String, Object> map =
- (HashMap<String, Object>) msg.obj;
- String url = (String) map.get("url");
- mVideoView.setVideoURI(Uri.parse(url));
- mVideoView.start();
- break;
- }
+ }
+ };
}
- /**
- * Play a video stream.
- * @param url is the URL of the video stream.
- * @param webview is the WebViewCore that is requesting the playback.
- */
- public void play(String url) {
- // We need to know the webview that is requesting the playback.
- Message message = obtainMessage(PLAY);
- HashMap<String, Object> map = new HashMap();
- map.put("url", url);
- message.obj = map;
+ private void doSetPoster(Bitmap poster) {
+ if (poster == null) {
+ return;
+ }
+ // Send the bitmap over to the UI thread.
+ Message message = obtainMessage(SET_POSTER);
+ message.obj = poster;
sendMessage(message);
}
+ public Context getContext() {
+ return mWebView.getContext();
+ }
+
+ // The public methods below are all called from WebKit only.
+ /**
+ * Play a video stream.
+ * @param url is the URL of the video stream.
+ */
+ public void play(String url) {
+ if (url == null) {
+ return;
+ }
+ Message message = obtainMessage(PLAY);
+ message.obj = url;
+ sendMessage(message);
+ }
+
+ /**
+ * Seek into the video stream.
+ * @param time is the position in the video stream.
+ */
+ public void seek(int time) {
+ Message message = obtainMessage(SEEK);
+ message.obj = new Integer(time);
+ sendMessage(message);
+ }
+
+ /**
+ * Pause the playback.
+ */
+ public void pause() {
+ Message message = obtainMessage(PAUSE);
+ sendMessage(message);
+ }
+
+ /**
+ * Create the child view that will cary the poster.
+ */
public void createView() {
mChildView = mWebView.mViewManager.createView();
sendMessage(obtainMessage(INIT));
}
+ /**
+ * Attach the poster view.
+ * @param x, y are the screen coordinates where the poster should be hung.
+ * @param width, height denote the size of the poster.
+ */
public void attachView(int x, int y, int width, int height) {
if (mChildView == null) {
return;
@@ -213,11 +430,36 @@
mChildView.attachView(x, y, width, height);
}
+ /**
+ * Remove the child view and, thus, the poster.
+ */
public void removeView() {
if (mChildView == null) {
return;
}
mChildView.removeView();
+ // This is called by the C++ MediaPlayerPrivate dtor.
+ // Cancel any active poster download.
+ if (mPosterDownloader != null) {
+ mPosterDownloader.cancelAndReleaseQueue();
+ }
+ }
+
+ /**
+ * Load the poster image.
+ * @param url is the URL of the poster image.
+ */
+ public void loadPoster(String url) {
+ if (url == null) {
+ return;
+ }
+ // Cancel any active poster download.
+ if (mPosterDownloader != null) {
+ mPosterDownloader.cancelAndReleaseQueue();
+ }
+ // Load the poster asynchronously
+ mPosterDownloader = new PosterDownloader(url, this);
+ mPosterDownloader.start();
}
/**
@@ -226,7 +468,10 @@
*
* @return a new HTML5VideoViewProxy object.
*/
- public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore) {
- return new HTML5VideoViewProxy(webViewCore.getWebView());
+ public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore, int nativePtr) {
+ return new HTML5VideoViewProxy(webViewCore.getWebView(), nativePtr);
}
+
+ private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
+ private native void nativeOnEnded(int nativePointer);
}
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 95b3a12..39a2470 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -16,6 +16,8 @@
package android.webkit;
+import com.android.internal.widget.EditableInputConnection;
+
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -38,6 +40,7 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
@@ -346,6 +349,16 @@
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
+ // This code is copied from TextView.onDraw(). That code does not get
+ // executed, however, because the WebTextView does not draw, allowing
+ // webkit's drawing to show through.
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null && imm.isActive(this)) {
+ Spannable sp = (Spannable) getText();
+ int candStart = EditableInputConnection.getComposingSpanStart(sp);
+ int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
+ imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
+ }
if (!mFromWebKit && mWebView != null) {
if (DebugFlags.WEB_TEXT_VIEW) {
Log.v(LOGTAG, "onSelectionChanged selStart=" + selStart
@@ -430,18 +443,26 @@
mGotTouchDown = true;
break;
case MotionEvent.ACTION_MOVE:
+ int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
Spannable buffer = getText();
int initialScrollX = Touch.getInitialScrollX(this, buffer);
int initialScrollY = Touch.getInitialScrollY(this, buffer);
super.onTouchEvent(event);
- if (mScrollX != initialScrollX
- || mScrollY != initialScrollY) {
+ if (Math.abs(mScrollX - initialScrollX) > slop
+ || Math.abs(mScrollY - initialScrollY) > slop) {
if (mWebView != null) {
mWebView.scrollFocusedTextInput(mScrollX, mScrollY);
}
mScrolled = true;
return true;
}
+ if (Math.abs((int) event.getX() - mDragStartX) < slop
+ && Math.abs((int) event.getY() - mDragStartY) < slop) {
+ // If the user has not scrolled further than slop, we should not
+ // send the drag. Instead, do nothing, and when the user lifts
+ // their finger, we will change the selection.
+ return true;
+ }
if (mWebView != null) {
// Only want to set the initial state once.
if (!mDragSent) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4ca17ac..a5536dd 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -420,6 +420,7 @@
private static final int STD_SPEED = 480; // pixels per second
// time for the longest scroll animation
private static final int MAX_DURATION = 750; // milliseconds
+ private static final int SLIDE_TITLE_DURATION = 300; // milliseconds
private Scroller mScroller;
private boolean mWrapContent;
@@ -2416,10 +2417,18 @@
if ((dx | dy) == 0) {
return false;
}
-
- if (true && animate) {
+ // mobile sites prefer to scroll to (0, 1), thus the + 1 below
+ boolean slideTitle = getVisibleTitleHeight() > 0
+ && y <= getTitleHeight() + 1;
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "pinScrollTo slideTitle=" + slideTitle
+ + " getVisibleTitleHeight()=" + getVisibleTitleHeight()
+ + " animationDuration=" + animationDuration + " y=" + y);
+ }
+ if (slideTitle || animate) {
// Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
-
+ if (slideTitle && animationDuration < SLIDE_TITLE_DURATION)
+ animationDuration = SLIDE_TITLE_DURATION;
mScroller.startScroll(mScrollX, mScrollY, dx, dy,
animationDuration > 0 ? animationDuration : computeDuration(dx, dy));
invalidate();
@@ -2754,7 +2763,8 @@
zoomScale = mZoomScale;
// set mZoomScale to be 0 as we have done animation
mZoomScale = 0;
- animateZoom = false; // inform drawContentPicture we're done
+ // call invalidate() again to draw with the final filters
+ invalidate();
if (mNeedToAdjustWebTextView) {
mNeedToAdjustWebTextView = false;
mWebTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
@@ -2899,6 +2909,8 @@
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (isTextView) {
+ if (mWebTextView == null) return;
+
imm.showSoftInput(mWebTextView, 0);
// Now we need to fake a touch event to place the cursor where the
// user touched.
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 4566c4c..953dd92 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1325,7 +1325,7 @@
final int maxHeight = mPopup.getMaxAvailableHeight(
getDropDownAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
- if (mDropDownAlwaysVisible) {
+ if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.FILL_PARENT) {
// getMaxAvailableHeight() subtracts the padding, so we put it back,
// to get the available height for the whole window
int padding = 0;
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index fe01866..4ec597c 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -42,6 +42,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
+import android.widget.FasttrackBadgeWidget;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@@ -64,15 +65,13 @@
private TextView mDisplayNameView;
private TextView mPhoneticNameView;
private CheckBox mStarredView;
- private ImageView mPhotoView;
+ private FasttrackBadgeWidget mPhotoView;
private ImageView mPresenceView;
private TextView mStatusView;
private int mNoPhotoResource;
private QueryHandler mQueryHandler;
- protected long mContactId;
protected Uri mContactUri;
- protected Uri mStatusUri;
protected String[] mExcludeMimes = null;
@@ -94,6 +93,8 @@
Contacts.STARRED,
Contacts.PHOTO_ID,
Contacts.PRESENCE_STATUS,
+ Contacts._ID,
+ Contacts.LOOKUP_KEY,
};
protected static final int HEADER_DISPLAY_NAME_COLUMN_INDEX = 0;
//TODO: We need to figure out how we're going to get the phonetic name.
@@ -101,6 +102,8 @@
protected static final int HEADER_STARRED_COLUMN_INDEX = 1;
protected static final int HEADER_PHOTO_ID_COLUMN_INDEX = 2;
protected static final int HEADER_PRESENCE_STATUS_COLUMN_INDEX = 3;
+ protected static final int HEADER_CONTACT_ID_COLUMN_INDEX = 4;
+ protected static final int HEADER_LOOKUP_KEY_COLUMN_INDEX = 5;
//Projection used for finding the most recent social status.
protected static final String[] SOCIAL_PROJECTION = new String[] {
@@ -113,18 +116,29 @@
//Projection used for looking up contact id from phone number
protected static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
PhoneLookup._ID,
+ PhoneLookup.LOOKUP_KEY,
};
protected static final int PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
+ protected static final int PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1;
//Projection used for looking up contact id from email address
protected static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
RawContacts.CONTACT_ID,
+ Contacts.LOOKUP_KEY,
};
protected static final int EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
+ protected static final int EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1;
+ protected static final String[] CONTACT_LOOKUP_PROJECTION = new String[] {
+ Contacts._ID,
+ };
+ protected static final int CONTACT_LOOKUP_ID_COLUMN_INDEX = 0;
private static final int TOKEN_CONTACT_INFO = 0;
private static final int TOKEN_SOCIAL = 1;
+ private static final int TOKEN_PHONE_LOOKUP = 2;
+ private static final int TOKEN_EMAIL_LOOKUP = 3;
+ private static final int TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY = 4;
public ContactHeaderWidget(Context context) {
this(context, null);
@@ -151,8 +165,7 @@
mStarredView = (CheckBox)findViewById(R.id.star);
mStarredView.setOnClickListener(this);
- mPhotoView = (ImageView)findViewById(R.id.photo);
- mPhotoView.setOnClickListener(this);
+ mPhotoView = (FasttrackBadgeWidget) findViewById(R.id.photo);
mPhotoView.setOnLongClickListener(this);
mPresenceView = (ImageView) findViewById(R.id.presence);
@@ -217,12 +230,46 @@
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
try{
- if (token == TOKEN_CONTACT_INFO) {
- bindContactInfo(cursor);
- invalidate();
- } else if (token == TOKEN_SOCIAL) {
- bindSocial(cursor);
- invalidate();
+ switch (token) {
+ case TOKEN_CONTACT_INFO: {
+ bindContactInfo(cursor);
+ invalidate();
+ break;
+ }
+ case TOKEN_SOCIAL: {
+ bindSocial(cursor);
+ invalidate();
+ break;
+ }
+ case TOKEN_PHONE_LOOKUP: {
+ if (cursor != null && cursor.moveToFirst()) {
+ long contactId = cursor.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX);
+ String lookupKey = cursor.getString(
+ PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
+ bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey));
+ } else {
+ setDisplayName((String) cookie, null);
+ }
+ break;
+ }
+ case TOKEN_EMAIL_LOOKUP: {
+ if (cursor != null && cursor.moveToFirst()) {
+ long contactId = cursor.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
+ String lookupKey = cursor.getString(
+ EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
+ bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey));
+ } else {
+ setDisplayName((String) cookie, null);
+ }
+ break;
+ }
+ case TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY: {
+ if (cursor != null && cursor.moveToFirst()) {
+ long contactId = cursor.getLong(CONTACT_LOOKUP_ID_COLUMN_INDEX);
+ startSocialQuery(ContentUris.withAppendedId(
+ Activities.CONTENT_CONTACT_STATUS_URI, contactId));
+ }
+ }
}
} finally {
if (cursor != null) {
@@ -300,33 +347,31 @@
* Convenience method for binding all available data from an existing
* contact.
*
- * @param contactId the contact id of the contact whose info should be displayed.
+ * @param conatctUri a {Contacts.CONTENT_LOOKUP_URI} style URI.
*/
- public void bindFromContactId(long contactId) {
- mContactId = contactId;
- mContactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, mContactId);
+ public void bindFromContactLookupUri(Uri contactLookupUri) {
+ mContactUri = contactLookupUri;
- bindContactUri(mContactUri);
- bindSocialUri(ContentUris.withAppendedId(Activities.CONTENT_CONTACT_STATUS_URI, mContactId));
+ // Query for the contactId so we can do the social query.
+ mQueryHandler.startQuery(TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY, null, contactLookupUri,
+ CONTACT_LOOKUP_PROJECTION, null, null, null);
+
+ startContactQuery(contactLookupUri);
}
/**
- * Convenience method for binding {@link Contacts} header details from a
- * {@link Contacts#CONTENT_URI} reference.
+ * Convenience method for binding all available data from an existing
+ * contact.
+ *
+ * @param conatctUri a {Contacts.CONTENT_URI} style URI.
*/
- public void bindContactUri(Uri contactUri) {
- mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, contactUri, HEADER_PROJECTION,
- null, null, null);
- }
+ public void bindFromContactUri(Uri contactUri) {
+ mContactUri = contactUri;
+ long contactId = ContentUris.parseId(contactUri);
- /**
- * Convenience method for binding {@link Activities} header details from a
- * {@link Activities#CONTENT_CONTACT_STATUS_URI}.
- */
- public void bindSocialUri(Uri contactSocial) {
- mStatusUri = contactSocial;
- mQueryHandler.startQuery(TOKEN_SOCIAL, null, mStatusUri, SOCIAL_PROJECTION, null, null,
- null);
+ startContactQuery(contactUri);
+ startSocialQuery(ContentUris.withAppendedId(
+ Activities.CONTENT_CONTACT_STATUS_URI, contactId));
}
/**
@@ -338,21 +383,9 @@
* address, one of them will be chosen to bind to.
*/
public void bindFromEmail(String emailAddress) {
- Cursor c = null;
- try {
- c = mContentResolver.query(Uri.withAppendedPath(Email.CONTENT_FILTER_EMAIL_URI, Uri
- .encode(emailAddress)), EMAIL_LOOKUP_PROJECTION, null, null, null);
- if (c != null && c.moveToFirst()) {
- long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
- bindFromContactId(contactId);
- } else {
- setDisplayName(emailAddress, null);
- }
- } finally {
- if (c != null) {
- c.close();
- }
- }
+ mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, emailAddress,
+ Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(emailAddress)),
+ EMAIL_LOOKUP_PROJECTION, null, null, null);
}
/**
@@ -364,22 +397,19 @@
* number, one of them will be chosen to bind to.
*/
public void bindFromPhoneNumber(String number) {
- Cursor c = null;
- try {
- c = mContentResolver.query(
- Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)),
- PHONE_LOOKUP_PROJECTION, null, null, null);
- if (c != null && c.moveToFirst()) {
- long contactId = c.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX);
- bindFromContactId(contactId);
- } else {
- setDisplayName(number, null);
- }
- } finally {
- if (c != null) {
- c.close();
- }
- }
+ mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, number,
+ Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
+ PHONE_LOOKUP_PROJECTION, null, null, null);
+ }
+
+ private void startSocialQuery(Uri contactSocial) {
+ mQueryHandler.startQuery(TOKEN_SOCIAL, null, contactSocial, SOCIAL_PROJECTION, null, null,
+ null);
+ }
+
+ private void startContactQuery(Uri contactUri) {
+ mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, contactUri, HEADER_PROJECTION,
+ null, null, null);
}
/**
@@ -390,6 +420,8 @@
// TODO: Bring back phonetic name
final String displayName = c.getString(HEADER_DISPLAY_NAME_COLUMN_INDEX);
+ final long contactId = c.getLong(HEADER_CONTACT_ID_COLUMN_INDEX);
+ final String lookupKey = c.getString(HEADER_LOOKUP_KEY_COLUMN_INDEX);
final String phoneticName = null;
this.setDisplayName(displayName, null);
@@ -402,6 +434,7 @@
photoBitmap = loadPlaceholderPhoto(null);
}
mPhotoView.setImageBitmap(photoBitmap);
+ mPhotoView.assignContactUri(Contacts.getLookupUri(contactId, lookupKey));
//Set the presence status
int presence = c.getInt(HEADER_PRESENCE_STATUS_COLUMN_INDEX);
@@ -423,27 +456,11 @@
return;
}
- switch (view.getId()) {
- case R.id.star: {
- // Toggle "starred" state
- final ContentValues values = new ContentValues(1);
- values.put(Contacts.STARRED, mStarredView.isChecked());
- mContentResolver.update(mContactUri, values, null, null);
- break;
- }
- case R.id.photo: {
- // Photo launches contact detail action
- final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mContactUri);
- final Rect target = getTargetRect(view);
- intent.putExtra(Intents.EXTRA_TARGET_RECT, target);
- intent.putExtra(Intents.EXTRA_MODE, Intents.MODE_SMALL);
- if (mExcludeMimes != null) {
- // Exclude specific MIME-types when requested
- intent.putExtra(Intents.EXTRA_EXCLUDE_MIMES, mExcludeMimes);
- }
- mContext.startActivity(intent);
- break;
- }
+ if (view.getId() == R.id.star) {
+ // Toggle "starred" state
+ final ContentValues values = new ContentValues(1);
+ values.put(Contacts.STARRED, mStarredView.isChecked());
+ mContentResolver.update(mContactUri, values, null, null);
}
}
diff --git a/core/java/com/android/internal/widget/RotarySelector.java b/core/java/com/android/internal/widget/RotarySelector.java
index 7b940c9..aff92b8 100644
--- a/core/java/com/android/internal/widget/RotarySelector.java
+++ b/core/java/com/android/internal/widget/RotarySelector.java
@@ -19,8 +19,6 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Vibrator;
import android.util.AttributeSet;
@@ -28,7 +26,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
-
+import static android.view.animation.AnimationUtils.currentAnimationTimeMillis;
import com.android.internal.R;
@@ -69,7 +67,7 @@
private boolean mAnimating = false;
private long mAnimationEndTime;
private int mAnimatingDelta;
- AccelerateInterpolator mInterpolator;
+ private AccelerateInterpolator mInterpolator;
/**
* True after triggering an action if the user of {@link OnDialTriggerListener} wants to
@@ -96,12 +94,6 @@
private static final long VIBRATE_SHORT = 60; // msec
private static final long VIBRATE_LONG = 100; // msec
- // Various tweakable layout or behavior parameters:
-
- // How close to the edge of the screen, we let the handle get before
- // triggering an action:
- private static final int EDGE_THRESHOLD_DIP = 70;
-
/**
* The drawable for the arrows need to be scrunched this many dips towards the rotary bg below
* it.
@@ -122,6 +114,11 @@
private static final boolean DRAW_CENTER_DIMPLE = false;
+ public RotarySelector(Context context) {
+ this(context, null);
+ }
+
+
/**
* Constructor used when this widget is created from a layout file.
*/
@@ -132,8 +129,6 @@
Resources r = getResources();
mDensity = r.getDisplayMetrics().density;
if (DBG) log("- Density: " + mDensity);
- // Density is 1.0 on HVGA (like Dream), and 1.5 on WVGA.
- // Usage: raw_pixel_value = (int) (dpi_value * mDensity + 0.5f)
// Assets (all are BitmapDrawables).
mBackground = r.getDrawable(R.drawable.jog_dial_bg_cropped);
@@ -143,6 +138,15 @@
mArrowLongRight = r.getDrawable(R.drawable.jog_dial_arrow_long_right_red);
mArrowShortLeftAndRight = r.getDrawable(R.drawable.jog_dial_arrow_short_left_and_right);
+ // Arrows:
+ // All arrow assets are the same size (they're the full width of
+ // the screen) regardless of which arrows are actually visible.
+ int arrowW = mArrowShortLeftAndRight.getIntrinsicWidth();
+ int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight();
+ mArrowShortLeftAndRight.setBounds(0, 0, arrowW, arrowH);
+ mArrowLongLeft.setBounds(0, 0, arrowW, arrowH);
+ mArrowLongRight.setBounds(0, 0, arrowW, arrowH);
+
mInterpolator = new AccelerateInterpolator();
}
@@ -237,7 +241,7 @@
// update animating state before we draw anything
if (mAnimating && !mFrozen) {
- long millisLeft = mAnimationEndTime - System.currentTimeMillis();
+ long millisLeft = mAnimationEndTime - currentAnimationTimeMillis();
if (DBG) log("millisleft for animating: " + millisLeft);
if (millisLeft <= 0) {
reset();
@@ -259,11 +263,6 @@
if (DBG) log(" Background BOUNDS: " + mBackground.getBounds());
mBackground.draw(canvas);
- // Arrows:
- // All arrow assets are the same size (they're the full width of
- // the screen) regardless of which arrows are actually visible.
- int arrowW = mArrowShortLeftAndRight.getIntrinsicWidth();
- int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight();
// Draw the correct arrow(s) depending on the current state:
Drawable currentArrow;
@@ -280,7 +279,6 @@
default:
throw new IllegalStateException("invalid mGrabbedState: " + mGrabbedState);
}
- currentArrow.setBounds(0, 0, arrowW, arrowH);
currentArrow.draw(canvas);
// debug: draw circle that should match the outer arc (good sanity check)
@@ -382,63 +380,70 @@
final int eventX = (int) event.getX();
final int hitWindow = mDimple.getIntrinsicWidth();
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- if (DBG) log("touch-down");
- mTriggered = false;
- if (mGrabbedState != RotarySelector.NOTHING_GRABBED) {
+ final int action = event.getAction();
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ if (DBG) log("touch-down");
+ mTriggered = false;
+ if (mGrabbedState != NOTHING_GRABBED) {
+ reset();
+ invalidate();
+ }
+ if (eventX < mLeftHandleX + hitWindow) {
+ mTouchDragOffset = eventX - mLeftHandleX;
+ mGrabbedState = LEFT_HANDLE_GRABBED;
+ invalidate();
+ vibrate(VIBRATE_SHORT);
+ } else if (eventX > mRightHandleX - hitWindow) {
+ mTouchDragOffset = eventX - mRightHandleX;
+ mGrabbedState = RIGHT_HANDLE_GRABBED;
+ invalidate();
+ vibrate(VIBRATE_SHORT);
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ if (DBG) log("touch-move");
+ if (mGrabbedState == LEFT_HANDLE_GRABBED) {
+ mTouchDragOffset = eventX - mLeftHandleX;
+ invalidate();
+ if (eventX >= mRightHandleX - EDGE_PADDING_DIP && !mTriggered) {
+ mTriggered = true;
+ mFrozen = dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
+ }
+ } else if (mGrabbedState == RIGHT_HANDLE_GRABBED) {
+ mTouchDragOffset = eventX - mRightHandleX;
+ invalidate();
+ if (eventX <= mLeftHandleX + EDGE_PADDING_DIP && !mTriggered) {
+ mTriggered = true;
+ mFrozen = dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
+ }
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if (DBG) log("touch-up");
+ // handle animating back to start if they didn't trigger
+ if (mGrabbedState == LEFT_HANDLE_GRABBED
+ && Math.abs(eventX - mLeftHandleX) > 5) {
+ mAnimating = true;
+ mAnimationEndTime = currentAnimationTimeMillis() + ANIMATION_DURATION_MILLIS;
+ mAnimatingDelta = eventX - mLeftHandleX;
+ } else if (mGrabbedState == RIGHT_HANDLE_GRABBED
+ && Math.abs(eventX - mRightHandleX) > 5) {
+ mAnimating = true;
+ mAnimationEndTime = currentAnimationTimeMillis() + ANIMATION_DURATION_MILLIS;
+ mAnimatingDelta = eventX - mRightHandleX;
+ }
+
+ mTouchDragOffset = 0;
+ mGrabbedState = NOTHING_GRABBED;
+ invalidate();
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ if (DBG) log("touch-cancel");
reset();
invalidate();
- }
- if (eventX < mLeftHandleX + hitWindow) {
- mTouchDragOffset = eventX - mLeftHandleX;
- mGrabbedState = RotarySelector.LEFT_HANDLE_GRABBED;
- invalidate();
- vibrate(VIBRATE_SHORT);
- } else if (eventX > mRightHandleX - hitWindow) {
- mTouchDragOffset = eventX - mRightHandleX;
- mGrabbedState = RotarySelector.RIGHT_HANDLE_GRABBED;
- invalidate();
- vibrate(VIBRATE_SHORT);
- }
- } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
- if (DBG) log("touch-move");
- if (mGrabbedState == RotarySelector.LEFT_HANDLE_GRABBED) {
- mTouchDragOffset = eventX - mLeftHandleX;
- invalidate();
- if (eventX >= mRightHandleX - EDGE_PADDING_DIP && !mTriggered) {
- mTriggered = true;
- mFrozen = dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
- }
- } else if (mGrabbedState == RotarySelector.RIGHT_HANDLE_GRABBED) {
- mTouchDragOffset = eventX - mRightHandleX;
- invalidate();
- if (eventX <= mLeftHandleX + EDGE_PADDING_DIP && !mTriggered) {
- mTriggered = true;
- mFrozen = dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
- }
- }
- } else if ((event.getAction() == MotionEvent.ACTION_UP)) {
- if (DBG) log("touch-up");
- // handle animating back to start if they didn't trigger
- if (mGrabbedState == RotarySelector.LEFT_HANDLE_GRABBED
- && Math.abs(eventX - mLeftHandleX) > 5) {
- mAnimating = true;
- mAnimationEndTime = System.currentTimeMillis() + ANIMATION_DURATION_MILLIS;
- mAnimatingDelta = eventX - mLeftHandleX;
- } else if (mGrabbedState == RotarySelector.RIGHT_HANDLE_GRABBED
- && Math.abs(eventX - mRightHandleX) > 5) {
- mAnimating = true;
- mAnimationEndTime = System.currentTimeMillis() + ANIMATION_DURATION_MILLIS;
- mAnimatingDelta = eventX - mRightHandleX;
- }
-
- mTouchDragOffset = 0;
- mGrabbedState = RotarySelector.NOTHING_GRABBED;
- invalidate();
- } else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
- if (DBG) log("touch-cancel");
- reset();
- invalidate();
+ break;
}
return true;
}
@@ -446,7 +451,7 @@
private void reset() {
mAnimating = false;
mTouchDragOffset = 0;
- mGrabbedState = RotarySelector.NOTHING_GRABBED;
+ mGrabbedState = NOTHING_GRABBED;
mTriggered = false;
}
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index a185d8d..ba13519 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -133,23 +133,13 @@
LOGV(__FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
- DBusError err;
- dbus_error_init(&err);
- DBusMessage *reply =
- dbus_func_args_timeout(env, nat->conn, -1, c_path,
- "org.bluez.AudioSink", "Connect",
- DBUS_TYPE_INVALID);
+ bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+ c_path, "org.bluez.AudioSink", "Connect",
+ DBUS_TYPE_INVALID);
+
env->ReleaseStringUTFChars(path, c_path);
-
- if (!reply && dbus_error_is_set(&err)) {
- LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
- return JNI_FALSE;
- } else if (!reply) {
- LOGE("DBus reply is NULL in function %s", __FUNCTION__);
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return ret ? JNI_TRUE : JNI_FALSE;
}
#endif
return JNI_FALSE;
@@ -161,23 +151,13 @@
LOGV(__FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
- DBusError err;
- dbus_error_init(&err);
- DBusMessage *reply =
- dbus_func_args_timeout(env, nat->conn, -1, c_path,
- "org.bluez.AudioSink", "Disconnect",
- DBUS_TYPE_INVALID);
+ bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+ c_path, "org.bluez.AudioSink", "Disconnect",
+ DBUS_TYPE_INVALID);
+
env->ReleaseStringUTFChars(path, c_path);
-
- if (!reply && dbus_error_is_set(&err)) {
- LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
- return JNI_FALSE;
- } else if (!reply) {
- LOGE("DBus reply is NULL in function %s", __FUNCTION__);
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return ret ? JNI_TRUE : JNI_FALSE;
}
#endif
return JNI_FALSE;
diff --git a/core/res/res/drawable-hdpi/ic_emergency.png b/core/res/res/drawable-hdpi/ic_emergency.png
index a2dd372..b4465ff 100644
--- a/core/res/res/drawable-hdpi/ic_emergency.png
+++ b/core/res/res/drawable-hdpi/ic_emergency.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_medium.png b/core/res/res/drawable-hdpi/title_bar_medium.png
new file mode 100644
index 0000000..c13dd26
--- /dev/null
+++ b/core/res/res/drawable-hdpi/title_bar_medium.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/title_bar_medium.png b/core/res/res/drawable-mdpi/title_bar_medium.png
new file mode 100644
index 0000000..9d01f79
--- /dev/null
+++ b/core/res/res/drawable-mdpi/title_bar_medium.png
Binary files differ
diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml
index 8d7e470..e800dfa 100644
--- a/core/res/res/layout/contact_header.xml
+++ b/core/res/res/layout/contact_header.xml
@@ -19,17 +19,17 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:background="@drawable/title_bar_tall"
+ android:background="@drawable/title_bar_medium"
android:paddingRight="5dip"
android:gravity="center_vertical">
- <ImageView android:id="@+id/photo"
- android:layout_width="56dip"
- android:layout_height="62dip"
+ <android.widget.FasttrackBadgeWidget android:id="@+id/photo"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
android:layout_marginRight="10dip"
android:layout_marginLeft="10dip"
- android:scaleType="fitCenter"
- android:background="@drawable/fasttrack_badge_middle_large"/>
+ style="@*android:style/Widget.FasttrackBadgeWidget.WindowSmall" />
+ />
<LinearLayout
android:layout_width="0dip"
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index 929d0a2..6dd2949 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -21,7 +21,8 @@
the user how to unlock their device, or make an emergency call. This
is the portrait layout. -->
-<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
@@ -34,31 +35,70 @@
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="1.0"
+ android:gravity="center_horizontal"
>
+ <TextView
+ android:id="@+id/carrier"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="5dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ />
+ <TextView
+ android:id="@+id/centerDot"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:layout_marginRight="5dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="17sp"
+ />
+ <TextView
+ android:id="@+id/time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="5dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textSize="35sp"
+ />
+ <TextView
+ android:id="@+id/date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="-12dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="17sp"
+ />
- <!-- lock icon next to header text -->
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dip"
- android:gravity="center"
- >
- <ImageView android:id="@+id/unlockLockIcon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="3dip"
- android:baselineAligned="true"
- android:gravity="center"
- android:src="@android:drawable/ic_lock_idle_lock"
- />
- <TextView android:id="@+id/headerText"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:textSize="18sp"/>
- </LinearLayout>
+ <View
+ android:id="@+id/divider"
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:layout_centerHorizontal="true"
+ android:background="@android:drawable/divider_horizontal_dark"
+ />
+
+ <!-- lock icon and header message -->
+ <TextView
+ android:id="@+id/headerText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dip"
+ android:layout_centerHorizontal="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="17sp"
+ android:drawableLeft="@drawable/ic_lock_idle_lock"
+ android:drawablePadding="4dip"
+ android:gravity="center"
+ />
<!-- fill space between header and button below -->
@@ -82,7 +122,7 @@
<Button android:id="@+id/emergencyCallAlone"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:text="@android:string/lockscreen_emergency_call"
+ android:text="@string/lockscreen_emergency_call"
android:textSize="14sp"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="8dip"
@@ -105,7 +145,7 @@
<Button android:id="@+id/emergencyCallTogether"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:text="@android:string/lockscreen_emergency_call"
+ android:text="@string/lockscreen_emergency_call"
android:textSize="14sp"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="8dip"
@@ -115,7 +155,7 @@
</LinearLayout>
<View
- android:background="@android:drawable/code_lock_left"
+ android:background="@drawable/code_lock_left"
android:layout_width="2dip"
android:layout_height="fill_parent" />
@@ -124,4 +164,4 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
-</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index a6c31b6..a5d44fc 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -23,54 +23,93 @@
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
- android:layout_width="wrap_content"
+ android:layout_width="fill_parent"
android:layout_height="fill_parent"
+ android:gravity="center_horizontal"
android:background="#A0000000"
>
- <!-- lock icon and header message -->
<LinearLayout
+ android:id="@+id/carrierAndDate"
android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1.0"
- android:gravity="center"
- >
-
- <ImageView android:id="@+id/unlockLockIcon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="13dip"
+ >
+ <TextView
+ android:id="@+id/carrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginRight="6dip"
- android:baselineAligned="true"
- android:gravity="center"
- android:src="@android:drawable/ic_lock_idle_lock"
- />
-
- <TextView android:id="@+id/headerText"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="17sp"
+ />
+ <TextView
+ android:id="@+id/centerDot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="center"
- android:textSize="18sp"/>
+ android:layout_marginLeft="5dip"
+ android:layout_marginRight="5dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="17sp"
+ />
+ <TextView
+ android:id="@+id/date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="17sp"
+ />
</LinearLayout>
+ <TextView
+ android:id="@+id/time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="-9dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textSize="48sp"
+ />
+
<View
- android:background="@android:drawable/code_lock_top"
- android:layout_width="fill_parent"
- android:layout_height="2dip" />
- <com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:id="@+id/divider"
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:layout_marginTop="-4dip"
+ android:layout_centerHorizontal="true"
+ android:background="@android:drawable/divider_horizontal_dark"
+ />
+
+ <!-- lock icon and header message -->
+ <TextView
+ android:id="@+id/headerText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dip"
+ android:layout_centerHorizontal="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="17sp"
+ android:drawableLeft="@drawable/ic_lock_idle_lock"
+ android:drawablePadding="4dip"
+ />
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:layout_marginTop="2dip"
/>
- <View
- android:background="@android:drawable/code_lock_bottom"
- android:layout_width="fill_parent"
- android:layout_height="8dip" />
<!-- footer -->
<FrameLayout
android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1.0"
+ android:layout_height="wrap_content"
>
<!-- option 1: a single emergency call button -->
@@ -82,8 +121,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
- android:text="@android:string/lockscreen_emergency_call"
- android:textSize="14sp"
+ android:text="@string/lockscreen_emergency_call"
+ android:textAppearance="?android:attr/textAppearanceSmall"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="8dip"
/>
@@ -105,8 +144,8 @@
android:layout_marginBottom="4dip"
android:layout_marginLeft="4dip"
android:layout_marginRight="2dip"
- android:text="@android:string/lockscreen_emergency_call"
- android:textSize="14sp"
+ android:text="@string/lockscreen_emergency_call"
+ android:textAppearance="?android:attr/textAppearanceSmall"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="8dip"
/>
@@ -118,7 +157,7 @@
android:layout_marginBottom="4dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="4dip"
- android:textSize="14sp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
android:visibility="invisible"
/>
</LinearLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a1a179b..eae838a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -530,6 +530,11 @@
lines, the IME should provide multiple lines if it can. Corresponds to
{@link android.text.InputType#TYPE_TEXT_FLAG_IME_MULTI_LINE}. -->
<flag name="textImeMultiLine" value="0x00040001" />
+ <!-- Can be combined with <var>text</var> and its variations to
+ indicate that the IME should not show any
+ dictionary-based word suggestions. Corresponds to
+ {@link android.text.InputType#TYPE_TEXT_FLAG_NO_SUGGESTIONS}. -->
+ <flag name="textNoSuggestions" value="0x00080001" />
<!-- Text that will be used as a URI. Corresponds to
{@link android.text.InputType#TYPE_CLASS_TEXT} |
{@link android.text.InputType#TYPE_TEXT_VARIATION_URI}. -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 62a230c..c967c4c 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -18,7 +18,7 @@
*/
-->
<resources>
- <drawable name="screen_background_light">#fff9f9f9</drawable>
+ <drawable name="screen_background_light">#ffffffff</drawable>
<drawable name="screen_background_dark">#ff202020</drawable>
<drawable name="status_bar_closed_default_background">#ff000000</drawable>
<drawable name="status_bar_opened_default_background">#ff000000</drawable>
@@ -45,7 +45,7 @@
<color name="dim_foreground_dark_inverse">#323232</color>
<color name="dim_foreground_dark_inverse_disabled">#80323232</color>
<color name="hint_foreground_dark">#808080</color>
- <color name="background_light">#fff9f9f9</color>
+ <color name="background_light">#ffffffff</color>
<color name="bright_foreground_light">#ff000000</color>
<color name="bright_foreground_light_inverse">#ffffffff</color>
<color name="bright_foreground_light_disabled">#80000000</color>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 69ddd63..bd79c75 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1962,7 +1962,7 @@
<string name="allow">Allow</string>
<string name="deny">Deny</string>
<string name="permission_request_notification_title">Permission Requested</string>
- <string name="permission_request_notification_subtitle">for account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g></string>
+ <string name="permission_request_notification_with_subtitle">Permission Requested\nfor account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g></string>
<!-- Label to show for a service that is running because it is an input method. -->
<string name="input_method_binding_label">Input method</string>
diff --git a/data/etc/Android.mk b/data/etc/Android.mk
index a32d8ea..041c5d3 100644
--- a/data/etc/Android.mk
+++ b/data/etc/Android.mk
@@ -32,3 +32,20 @@
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
+
+########################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := required_hardware.xml
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+#
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/data/etc/android.hardware.camera.flash-autofocus.xml b/data/etc/android.hardware.camera.flash-autofocus.xml
new file mode 100644
index 0000000..55f1900
--- /dev/null
+++ b/data/etc/android.hardware.camera.flash-autofocus.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This is the standard set of features for a camera with a flash. Note
+ that this currently requires having auto-focus as well. -->
+<permissions>
+ <feature name="android.hardware.camera" />
+ <feature name="android.hardware.camera.autofocus" />
+ <feature name="android.hardware.camera.flash" />
+</permissions>
diff --git a/data/etc/android.hardware.sensor.light.xml b/data/etc/android.hardware.sensor.light.xml
new file mode 100644
index 0000000..78b0fec
--- /dev/null
+++ b/data/etc/android.hardware.sensor.light.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Feature for devices with an ambient light sensor. -->
+<permissions>
+ <feature name="android.hardware.sensor.light" />
+</permissions>
diff --git a/data/etc/android.hardware.sensor.proximity.xml b/data/etc/android.hardware.sensor.proximity.xml
new file mode 100644
index 0000000..d1948de
--- /dev/null
+++ b/data/etc/android.hardware.sensor.proximity.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Feature for devices with a proximity sensor. -->
+<permissions>
+ <feature name="android.hardware.sensor.proximity" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.cdma.xml b/data/etc/android.hardware.telephony.cdma.xml
new file mode 100644
index 0000000..72e0485
--- /dev/null
+++ b/data/etc/android.hardware.telephony.cdma.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This is the standard set of features for a CDMA phone. -->
+<permissions>
+ <feature name="android.hardware.telephony" />
+ <feature name="android.hardware.telephony.cdma" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.gsm.xml b/data/etc/android.hardware.telephony.gsm.xml
new file mode 100644
index 0000000..ffde433
--- /dev/null
+++ b/data/etc/android.hardware.telephony.gsm.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This is the standard set of features for a GSM phone. -->
+<permissions>
+ <feature name="android.hardware.telephony" />
+ <feature name="android.hardware.telephony.gsm" />
+</permissions>
diff --git a/data/etc/required_hardware.xml b/data/etc/required_hardware.xml
new file mode 100644
index 0000000..896a148
--- /dev/null
+++ b/data/etc/required_hardware.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- These are the hardware features that all devices must possess.
+ These are always added for you by the build system, you do not need
+ to add them yourself. -->
+<permissions>
+ <feature name="android.hardware.sensor.compass" />
+ <feature name="android.hardware.sensor.accelerometer" />
+ <feature name="android.hardware.bluetooth" />
+ <feature name="android.hardware.wifi" />
+</permissions>
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 3266f1e..c6f57d4 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -36,7 +36,6 @@
private Drawable mCurrDrawable;
private int mAlpha = 0xFF;
private ColorFilter mColorFilter;
- private boolean mDither = DEFAULT_DITHER;
private int mCurIndex = -1;
private boolean mMutated;
@@ -83,10 +82,10 @@
@Override
public void setDither(boolean dither) {
- if (mDither != dither) {
- mDither = dither;
+ if (mDrawableContainerState.mDither != dither) {
+ mDrawableContainerState.mDither = dither;
if (mCurrDrawable != null) {
- mCurrDrawable.setDither(mDither);
+ mCurrDrawable.setDither(mDrawableContainerState.mDither);
}
}
}
@@ -212,7 +211,7 @@
if (d != null) {
d.setVisible(isVisible(), true);
d.setAlpha(mAlpha);
- d.setDither(mDither);
+ d.setDither(mDrawableContainerState.mDither);
d.setColorFilter(mColorFilter);
d.setState(getState());
d.setLevel(getLevel());
@@ -285,6 +284,8 @@
boolean mCanConstantState;
boolean mPaddingChecked = false;
+
+ boolean mDither = DEFAULT_DITHER;
DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
Resources res) {
@@ -323,6 +324,8 @@
mOpacity = orig.mOpacity;
mHaveStateful = orig.mHaveStateful;
mStateful = orig.mStateful;
+
+ mDither = orig.mDither;
} else {
mDrawables = new Drawable[10];
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 89db4fa..d35c5e3 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -140,6 +140,8 @@
native void nScriptSetTimeZone(int script, byte[] timeZone);
native void nScriptSetType(int type, boolean writable, String name, int slot);
native void nScriptSetRoot(boolean isRoot);
+ native void nScriptSetInvokable(String name, int slot);
+ native void nScriptInvoke(int id, int slot);
native void nScriptCBegin();
native void nScriptCSetScript(byte[] script, int offset, int length);
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index a402471..35791a3 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -25,6 +25,22 @@
boolean mIsRoot;
Type[] mTypes;
boolean[] mWritable;
+ Invokable[] mInvokables;
+
+ public static class Invokable {
+ RenderScript mRS;
+ Script mScript;
+ int mSlot;
+ String mName;
+
+ Invokable() {
+ mSlot = -1;
+ }
+
+ public void execute() {
+ mRS.nScriptInvoke(mScript.mID, mSlot);
+ }
+ }
Script(int id, RenderScript rs) {
super(rs);
@@ -61,12 +77,15 @@
Type[] mTypes;
String[] mNames;
boolean[] mWritable;
+ int mInvokableCount = 0;
+ Invokable[] mInvokables;
Builder(RenderScript rs) {
mRS = rs;
mTypes = new Type[MAX_SLOT];
mNames = new String[MAX_SLOT];
mWritable = new boolean[MAX_SLOT];
+ mInvokables = new Invokable[MAX_SLOT];
}
public void setType(Type t, int slot) {
@@ -79,6 +98,15 @@
mNames[slot] = name;
}
+ public Invokable addInvokable(String func) {
+ Invokable i = new Invokable();
+ i.mName = func;
+ i.mRS = mRS;
+ i.mSlot = mInvokableCount;
+ mInvokables[mInvokableCount++] = i;
+ return i;
+ }
+
public void setType(boolean writable, int slot) {
mWritable[slot] = writable;
}
@@ -90,11 +118,20 @@
mRS.nScriptSetType(mTypes[ct].mID, mWritable[ct], mNames[ct], ct);
}
}
+ for(int ct=0; ct < mInvokableCount; ct++) {
+ mRS.nScriptSetInvokable(mInvokables[ct].mName, ct);
+ }
}
void transferObject(Script s) {
s.mIsRoot = mIsRoot;
s.mTypes = mTypes;
+ s.mInvokables = new Invokable[mInvokableCount];
+ for(int ct=0; ct < mInvokableCount; ct++) {
+ s.mInvokables[ct] = mInvokables[ct];
+ s.mInvokables[ct].mScript = s;
+ }
+ s.mInvokables = null;
}
public void setRoot(boolean r) {
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 90b5958..eae6f24 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -891,6 +891,29 @@
}
static void
+nScriptSetInvoke(JNIEnv *_env, jobject _this, jstring _str, jint slot)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptSetInvoke, con(%p)", con);
+ const char* n = NULL;
+ if (_str) {
+ n = _env->GetStringUTFChars(_str, NULL);
+ }
+ rsScriptSetInvoke(con, n, slot);
+ if (n) {
+ _env->ReleaseStringUTFChars(_str, n);
+ }
+}
+
+static void
+nScriptInvoke(JNIEnv *_env, jobject _this, jint obj, jint slot)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptInvoke, con(%p), script(%p)", con, (void *)obj);
+ rsScriptInvoke(con, (RsScript)obj, slot);
+}
+
+static void
nScriptSetRoot(JNIEnv *_env, jobject _this, jboolean isRoot)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
@@ -1366,6 +1389,8 @@
{"nScriptSetTimeZone", "(I[B)V", (void*)nScriptSetTimeZone },
{"nScriptSetType", "(IZLjava/lang/String;I)V", (void*)nScriptSetType },
{"nScriptSetRoot", "(Z)V", (void*)nScriptSetRoot },
+{"nScriptSetInvokable", "(Ljava/lang/String;I)V", (void*)nScriptSetInvoke },
+{"nScriptInvoke", "(II)V", (void*)nScriptInvoke },
{"nScriptCBegin", "()V", (void*)nScriptCBegin },
{"nScriptCSetScript", "([BII)V", (void*)nScriptCSetScript },
diff --git a/include/private/ui/SharedBufferStack.h b/include/private/ui/SharedBufferStack.h
index 8b0f154..c02b2e7 100644
--- a/include/private/ui/SharedBufferStack.h
+++ b/include/private/ui/SharedBufferStack.h
@@ -69,12 +69,6 @@
// ----------------------------------------------------------------------------
-struct FlatRegion { // 12 bytes
- static const unsigned int NUM_RECT_MAX = 1;
- uint32_t count;
- uint16_t rects[4*NUM_RECT_MAX];
-};
-
// should be 128 bytes (32 longs)
class SharedBufferStack
{
@@ -84,6 +78,18 @@
friend class SharedBufferServer;
public:
+ struct FlatRegion { // 12 bytes
+ static const unsigned int NUM_RECT_MAX = 1;
+ uint32_t count;
+ uint16_t rects[4*NUM_RECT_MAX];
+ };
+
+ struct Statistics { // 4 longs
+ typedef int32_t usecs_t;
+ usecs_t totalTime;
+ usecs_t reserved[3];
+ };
+
SharedBufferStack();
void init(int32_t identity);
status_t setDirtyRegion(int buffer, const Region& reg);
@@ -100,7 +106,8 @@
volatile int32_t reallocMask;
int32_t identity; // surface's identity (const)
- int32_t reserved32[13];
+ int32_t reserved32[9];
+ Statistics stats;
FlatRegion dirtyRegion[NUM_BUFFER_MAX]; // 12*4=48 bytes
};
@@ -223,7 +230,7 @@
status_t queue(int buf);
bool needNewBuffer(int buffer) const;
status_t setDirtyRegion(int buffer, const Region& reg);
-
+
private:
friend struct Condition;
friend struct DequeueCondition;
@@ -257,6 +264,8 @@
};
int32_t tail;
+ // statistics...
+ nsecs_t mDequeueTime[NUM_BUFFER_MAX];
};
// ----------------------------------------------------------------------------
@@ -275,6 +284,9 @@
Region getDirtyRegion(int buffer) const;
+ SharedBufferStack::Statistics getStats() const;
+
+
private:
struct UnlockUpdate : public UpdateBase {
const int lockedBuffer;
diff --git a/keystore/java/android/security/ServiceCommand.java b/keystore/java/android/security/ServiceCommand.java
index ee80014..9923011 100644
--- a/keystore/java/android/security/ServiceCommand.java
+++ b/keystore/java/android/security/ServiceCommand.java
@@ -49,8 +49,6 @@
public static final int BUFFER_LENGTH = 4096;
- private static final boolean DBG = true;
-
private String mServiceName;
private String mTag;
private InputStream mIn;
@@ -61,7 +59,6 @@
if (mSocket != null) {
return true;
}
- if (DBG) Log.d(mTag, "connecting...");
try {
mSocket = new LocalSocket();
@@ -80,7 +77,6 @@
}
private void disconnect() {
- if (DBG) Log.d(mTag,"disconnecting...");
try {
if (mSocket != null) mSocket.close();
} catch (IOException ex) { }
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index ac2e738..87ad97c 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -297,6 +297,16 @@
param const char * name
}
+ScriptSetInvoke {
+ param const char * name
+ param uint32_t slot
+ }
+
+ScriptInvoke {
+ param RsScript s
+ param uint32_t slot
+ }
+
ScriptSetRoot {
param bool isRoot
}
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index fde31a1..99a085d 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -27,6 +27,8 @@
mEnviroment.mClearColor[2] = 0;
mEnviroment.mClearColor[3] = 1;
mEnviroment.mClearDepth = 1;
+ mEnviroment.mClearStencil = 0;
+ mEnviroment.mIsRoot = false;
}
Script::~Script()
@@ -83,10 +85,23 @@
}
}
+void rsi_ScriptSetInvoke(Context *rsc, const char *name, uint32_t slot)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mInvokableNames[slot] = name;
+}
+
+void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->mEnviroment.mInvokables[slot]();
+}
+
+
void rsi_ScriptSetRoot(Context * rsc, bool isRoot)
{
ScriptCState *ss = &rsc->mScriptC;
- ss->mEnviroment.mIsRoot = isRoot;
+ ss->mScript->mEnviroment.mIsRoot = isRoot;
}
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index 60f83a6..e40531e 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -34,6 +34,7 @@
class Script : public ObjectBase
{
public:
+ typedef void (* InvokeFunc_t)(void);
Script();
virtual ~Script();
@@ -52,17 +53,22 @@
ObjectBaseRef<ProgramFragment> mFragment;
//ObjectBaseRef<ProgramRaster> mRaster;
ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
-
+ InvokeFunc_t mInvokables[MAX_SCRIPT_BANKS];
+ const char * mScriptText;
+ uint32_t mScriptTextLength;
};
Enviroment_t mEnviroment;
uint32_t mCounstantBufferCount;
+
ObjectBaseRef<Allocation> mSlots[MAX_SCRIPT_BANKS];
ObjectBaseRef<const Type> mTypes[MAX_SCRIPT_BANKS];
String8 mSlotNames[MAX_SCRIPT_BANKS];
bool mSlotWritable[MAX_SCRIPT_BANKS];
+
+
virtual bool run(Context *, uint32_t launchID) = 0;
};
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 8230cbc..108ae5a 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -82,36 +82,27 @@
ScriptCState::ScriptCState()
{
+ mScript = NULL;
clear();
}
ScriptCState::~ScriptCState()
{
- if (mAccScript) {
- accDeleteScript(mAccScript);
- }
+ delete mScript;
+ mScript = NULL;
}
void ScriptCState::clear()
{
- memset(&mProgram, 0, sizeof(mProgram));
-
for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
mConstantBufferTypes[ct].clear();
mSlotNames[ct].setTo("");
+ mInvokableNames[ct].setTo("");
mSlotWritable[ct] = false;
}
- memset(&mEnviroment, 0, sizeof(mEnviroment));
- mEnviroment.mClearColor[0] = 0;
- mEnviroment.mClearColor[1] = 0;
- mEnviroment.mClearColor[2] = 0;
- mEnviroment.mClearColor[3] = 1;
- mEnviroment.mClearDepth = 1;
- mEnviroment.mClearStencil = 0;
- mEnviroment.mIsRoot = false;
-
- mAccScript = NULL;
+ delete mScript;
+ mScript = new ScriptC();
mInt32Defines.clear();
mFloatDefines.clear();
@@ -127,9 +118,9 @@
return NULL;
}
-void ScriptCState::runCompiler(Context *rsc)
+void ScriptCState::runCompiler(Context *rsc, ScriptC *s)
{
- mAccScript = accCreateScript();
+ s->mAccScript = accCreateScript();
String8 tmp;
rsc->appendNameDefines(&tmp);
@@ -139,44 +130,51 @@
appendTypes(&tmp);
tmp.append("#line 1\n");
- const char* scriptSource[] = {tmp.string(), mProgram.mScriptText};
- int scriptLength[] = {tmp.length(), mProgram.mScriptTextLength} ;
- accScriptSource(mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength);
- accRegisterSymbolCallback(mAccScript, symbolLookup, NULL);
- accCompileScript(mAccScript);
- accGetScriptLabel(mAccScript, "main", (ACCvoid**) &mProgram.mScript);
- accGetScriptLabel(mAccScript, "init", (ACCvoid**) &mProgram.mInit);
- rsAssert(mProgram.mScript);
+ const char* scriptSource[] = {tmp.string(), s->mEnviroment.mScriptText};
+ int scriptLength[] = {tmp.length(), s->mEnviroment.mScriptTextLength} ;
+ accScriptSource(s->mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength);
+ accRegisterSymbolCallback(s->mAccScript, symbolLookup, NULL);
+ accCompileScript(s->mAccScript);
+ accGetScriptLabel(s->mAccScript, "main", (ACCvoid**) &s->mProgram.mScript);
+ accGetScriptLabel(s->mAccScript, "init", (ACCvoid**) &s->mProgram.mInit);
+ rsAssert(s->mProgram.mScript);
- if (!mProgram.mScript) {
+ if (!s->mProgram.mScript) {
ACCchar buf[4096];
ACCsizei len;
- accGetScriptInfoLog(mAccScript, sizeof(buf), &len, buf);
+ accGetScriptInfoLog(s->mAccScript, sizeof(buf), &len, buf);
LOGE(buf);
}
- if (mProgram.mInit) {
- mProgram.mInit();
+ if (s->mProgram.mInit) {
+ s->mProgram.mInit();
}
for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
if (mSlotNames[ct].length() > 0) {
- accGetScriptLabel(mAccScript,
+ accGetScriptLabel(s->mAccScript,
mSlotNames[ct].string(),
- (ACCvoid**) &mProgram.mSlotPointers[ct]);
- LOGE("var %s %p", mSlotNames[ct].string(), mProgram.mSlotPointers[ct]);
+ (ACCvoid**) &s->mProgram.mSlotPointers[ct]);
}
}
- mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
- mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
- mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
+ for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
+ if (mInvokableNames[ct].length() > 0) {
+ accGetScriptLabel(s->mAccScript,
+ mInvokableNames[ct].string(),
+ (ACCvoid**) &s->mEnviroment.mInvokables[ct]);
+ }
+ }
- if (mProgram.mScript) {
+ s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
+ s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
+ s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
+
+ if (s->mProgram.mScript) {
const static int pragmaMax = 16;
ACCsizei pragmaCount;
ACCchar * str[pragmaMax];
- accGetPragmas(mAccScript, &pragmaCount, pragmaMax, &str[0]);
+ accGetPragmas(s->mAccScript, &pragmaCount, pragmaMax, &str[0]);
for (int ct=0; ct < pragmaCount; ct+=2) {
if (!strcmp(str[ct], "version")) {
@@ -188,12 +186,12 @@
continue;
}
if (!strcmp(str[ct+1], "parent")) {
- mEnviroment.mVertex.clear();
+ s->mEnviroment.mVertex.clear();
continue;
}
ProgramVertex * pv = (ProgramVertex *)rsc->lookupName(str[ct+1]);
if (pv != NULL) {
- mEnviroment.mVertex.set(pv);
+ s->mEnviroment.mVertex.set(pv);
continue;
}
LOGE("Unreconized value %s passed to stateVertex", str[ct+1]);
@@ -208,12 +206,12 @@
continue;
}
if (!strcmp(str[ct+1], "parent")) {
- mEnviroment.mFragment.clear();
+ s->mEnviroment.mFragment.clear();
continue;
}
ProgramFragment * pf = (ProgramFragment *)rsc->lookupName(str[ct+1]);
if (pf != NULL) {
- mEnviroment.mFragment.set(pf);
+ s->mEnviroment.mFragment.set(pf);
continue;
}
LOGE("Unreconized value %s passed to stateFragment", str[ct+1]);
@@ -224,13 +222,13 @@
continue;
}
if (!strcmp(str[ct+1], "parent")) {
- mEnviroment.mFragmentStore.clear();
+ s->mEnviroment.mFragmentStore.clear();
continue;
}
ProgramFragmentStore * pfs =
(ProgramFragmentStore *)rsc->lookupName(str[ct+1]);
if (pfs != NULL) {
- mEnviroment.mFragmentStore.set(pfs);
+ s->mEnviroment.mFragmentStore.set(pfs);
continue;
}
LOGE("Unreconized value %s passed to stateFragmentStore", str[ct+1]);
@@ -351,33 +349,6 @@
s.append(";\n");
LOGD(s);
str->append(s);
-#if 0
- for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) {
- const Component *c = e->getComponent(ct2);
- tmp.setTo("#define ");
- tmp.append(mSlotNames[ct]);
- tmp.append("_");
- tmp.append(c->getComponentName());
- switch (c->getType()) {
- case Component::FLOAT:
- tmp.append(" loadF(");
- break;
- case Component::SIGNED:
- sprintf(buf, " loadI%i(", c->getBits());
- tmp.append(buf);
- break;
- case Component::UNSIGNED:
- sprintf(buf, " loadU%i(", c->getBits());
- tmp.append(buf);
- break;
- }
- sprintf(buf, "%i, %i)\n", ct, ct2);
- tmp.append(buf);
-
- LOGD(tmp);
- str->append(tmp);
- }
-#endif
}
}
}
@@ -394,15 +365,16 @@
void rsi_ScriptCSetScript(Context * rsc, void *vp)
{
- ScriptCState *ss = &rsc->mScriptC;
- ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp);
+ rsAssert(0);
+ //ScriptCState *ss = &rsc->mScriptC;
+ //ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp);
}
void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
{
ScriptCState *ss = &rsc->mScriptC;
- ss->mProgram.mScriptText = text;
- ss->mProgram.mScriptTextLength = len;
+ ss->mScript->mEnviroment.mScriptText = text;
+ ss->mScript->mEnviroment.mScriptTextLength = len;
}
@@ -410,14 +382,11 @@
{
ScriptCState *ss = &rsc->mScriptC;
- ss->runCompiler(rsc);
+ ScriptC *s = ss->mScript;
+ ss->mScript = NULL;
- ScriptC *s = new ScriptC();
+ ss->runCompiler(rsc, s);
s->incUserRef();
- s->mAccScript = ss->mAccScript;
- ss->mAccScript = NULL;
- s->mEnviroment = ss->mEnviroment;
- s->mProgram = ss->mProgram;
for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get());
s->mSlotNames[ct] = ss->mSlotNames[ct];
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 8aa99ef..355f0c3 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -67,17 +67,15 @@
ScriptCState();
~ScriptCState();
- ACCscript* mAccScript;
-
- ScriptC::Program_t mProgram;
- Script::Enviroment_t mEnviroment;
+ ScriptC *mScript;
ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS];
String8 mSlotNames[MAX_SCRIPT_BANKS];
bool mSlotWritable[MAX_SCRIPT_BANKS];
+ String8 mInvokableNames[MAX_SCRIPT_BANKS];
void clear();
- void runCompiler(Context *rsc);
+ void runCompiler(Context *rsc, ScriptC *s);
void appendVarDefines(String8 *str);
void appendTypes(String8 *str);
diff --git a/libs/surfaceflinger/BlurFilter.cpp b/libs/surfaceflinger/BlurFilter.cpp
index 5dc0ba0..1ffbd5b 100644
--- a/libs/surfaceflinger/BlurFilter.cpp
+++ b/libs/surfaceflinger/BlurFilter.cpp
@@ -111,6 +111,50 @@
}
};
+template <int FACTOR = 0>
+struct BlurColor888X
+{
+ typedef uint32_t type;
+ int r, g, b;
+ inline BlurColor888X() { }
+ inline BlurColor888X(uint32_t v) {
+ v = BLUR_RGBA_TO_HOST(v);
+ r = v & 0xFF;
+ g = (v >> 8) & 0xFF;
+ b = (v >> 16) & 0xFF;
+ }
+ inline void clear() { r=g=b=0; }
+ inline uint32_t to(int shift, int last, int dither) const {
+ int R = r;
+ int G = g;
+ int B = b;
+ if (UNLIKELY(last)) {
+ if (FACTOR>0) {
+ int L = (R+G+G+B)>>2;
+ R += ((L - R) * FACTOR) >> 8;
+ G += ((L - G) * FACTOR) >> 8;
+ B += ((L - B) * FACTOR) >> 8;
+ }
+ }
+ R >>= shift;
+ G >>= shift;
+ B >>= shift;
+ return BLUR_HOST_TO_RGBA((0xFF<<24) | (B<<16) | (G<<8) | R);
+ }
+ inline BlurColor888X& operator += (const BlurColor888X& rhs) {
+ r += rhs.r;
+ g += rhs.g;
+ b += rhs.b;
+ return *this;
+ }
+ inline BlurColor888X& operator -= (const BlurColor888X& rhs) {
+ r -= rhs.r;
+ g -= rhs.g;
+ b -= rhs.b;
+ return *this;
+ }
+};
+
struct BlurGray565
{
typedef uint16_t type;
@@ -316,7 +360,13 @@
int kernelSizeUser,
int repeat)
{
- return blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+ status_t err = BAD_VALUE;
+ if (image->format == GGL_PIXEL_FORMAT_RGB_565) {
+ err = blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+ } else if (image->format == GGL_PIXEL_FORMAT_RGBX_8888) {
+ err = blurFilter< BlurColor888X<0x80> >(image, image, kernelSizeUser, repeat);
+ }
+ return err;
}
} // namespace android
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index d893f0a..cc913cbd 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -174,6 +174,13 @@
surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
+ if (mFlags & UPDATE_ON_DEMAND) {
+ // if we have update on demand, we definitely don't need to
+ // preserve the backbuffer, which is usually costly.
+ eglSurfaceAttrib(display, surface,
+ EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
+ }
+
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
if (dummy == EGL_BUFFER_PRESERVED) {
mFlags |= BUFFER_PRESERVED;
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 1e7f1e6..7387c85 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -303,7 +303,6 @@
// Index of the back buffer
const bool backbufferChanged = (front.w != temp.w) || (front.h != temp.h);
-
if (backbufferChanged) {
// the size changed, we need to ask our client to request a new buffer
LOGD_IF(DEBUG_RESIZE,
@@ -318,17 +317,6 @@
// buffer, it'll get the new size.
setDrawingSize(temp.w, temp.h);
- // all buffers need reallocation
- lcblk->reallocate();
-
- // recompute the visible region
- // FIXME: ideally we would do that only when we have received
- // a buffer of the right size
- flags |= Layer::eVisibleRegion;
- this->contentDirty = true;
-
-#if 0
- // FIXME: handle freeze lock
// we're being resized and there is a freeze display request,
// acquire a freeze lock, so that the screen stays put
// until we've redrawn at the new size; this is to avoid
@@ -340,7 +328,12 @@
mFreezeLock = mFlinger->getFreezeLock();
}
}
-#endif
+
+ // recompute the visible region
+ flags |= Layer::eVisibleRegion;
+ this->contentDirty = true;
+ // all buffers need reallocation
+ lcblk->reallocate();
}
if (temp.sequence != front.sequence) {
@@ -382,6 +375,13 @@
const Region dirty(lcblk->getDirtyRegion(buf));
mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
+
+ const Layer::State& front(drawingState());
+ if (newFrontBuffer->getWidth() == front.w &&
+ newFrontBuffer->getHeight() ==front.h) {
+ mFreezeLock.clear();
+ }
+
// FIXME: signal an event if we have more buffers waiting
// mFlinger->signalEvent();
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index e14f35b..0ef663f 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -40,9 +40,9 @@
LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& client, int32_t i)
- : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
- mRefreshCache(true), mCacheAge(0), mTextureName(-1U),
- mWidthScale(1.0f), mHeightScale(1.0f)
+: LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
+mRefreshCache(true), mCacheAge(0), mTextureName(-1U),
+mWidthScale(1.0f), mHeightScale(1.0f)
{
}
@@ -136,6 +136,13 @@
// create the texture name the first time
// can't do that in the ctor, because it runs in another thread.
glGenTextures(1, &mTextureName);
+ glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &mReadFormat);
+ glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &mReadType);
+ if (mReadFormat != GL_RGB || mReadType != GL_UNSIGNED_SHORT_5_6_5) {
+ mReadFormat = GL_RGBA;
+ mReadType = GL_UNSIGNED_BYTE;
+ mBlurFormat = GGL_PIXEL_FORMAT_RGBX_8888;
+ }
}
Region::const_iterator it = clip.begin();
@@ -143,33 +150,39 @@
if (it != end) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mTextureName);
-
+
if (mRefreshCache) {
mRefreshCache = false;
mAutoRefreshPending = false;
-
- // allocate enough memory for 4-bytes (2 pixels) aligned data
- const int32_t s = (w + 1) & ~1;
- uint16_t* const pixels = (uint16_t*)malloc(s*h*2);
+
+ int32_t pixelSize = 4;
+ int32_t s = w;
+ if (mReadType == GL_UNSIGNED_SHORT_5_6_5) {
+ // allocate enough memory for 4-bytes (2 pixels) aligned data
+ s = (w + 1) & ~1;
+ pixelSize = 2;
+ }
+
+ uint16_t* const pixels = (uint16_t*)malloc(s*h*pixelSize);
// This reads the frame-buffer, so a h/w GL would have to
// finish() its rendering first. we don't want to do that
// too often. Read data is 4-bytes aligned.
- glReadPixels(X, Y, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
-
+ glReadPixels(X, Y, w, h, mReadFormat, mReadType, pixels);
+
// blur that texture.
GGLSurface bl;
bl.version = sizeof(GGLSurface);
bl.width = w;
bl.height = h;
bl.stride = s;
- bl.format = GGL_PIXEL_FORMAT_RGB_565;
+ bl.format = mBlurFormat;
bl.data = (GGLubyte*)pixels;
blurFilter(&bl, 8, 2);
if (mFlags & (DisplayHardware::NPOT_EXTENSION)) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+ glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, w, h, 0,
+ mReadFormat, mReadType, pixels);
mWidthScale = 1.0f / w;
mHeightScale =-1.0f / h;
mYOffset = 0;
@@ -178,10 +191,10 @@
GLuint th = 1 << (31 - clz(h));
if (tw < w) tw <<= 1;
if (th < h) th <<= 1;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, tw, th, 0,
+ mReadFormat, mReadType, NULL);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+ mReadFormat, mReadType, pixels);
mWidthScale = 1.0f / tw;
mHeightScale =-1.0f / th;
mYOffset = th-h;
@@ -189,7 +202,7 @@
free((void*)pixels);
}
-
+
const State& s = drawingState();
if (UNLIKELY(s.alpha < 0xFF)) {
const GGLfixed alpha = (s.alpha << 16)/255;
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
index bf36ae4..2e9d7c6 100644
--- a/libs/surfaceflinger/LayerBlur.h
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -59,6 +59,9 @@
mutable GLfloat mWidthScale;
mutable GLfloat mHeightScale;
mutable GLfloat mYOffset;
+ mutable GLint mReadFormat;
+ mutable GLint mReadType;
+ mutable uint32_t mBlurFormat;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 38a897d..667571b 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -595,6 +595,7 @@
*overlayRef = new OverlayRef(mOverlayHandle, channel,
mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
+ mLayer.mFlinger->signalEvent();
}
LayerBuffer::OverlaySource::~OverlaySource()
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index a352431..31b5128c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -1521,6 +1521,7 @@
/*** Layer ***/
sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get());
if (l != 0) {
+ SharedBufferStack::Statistics stats = l->lcblk->getStats();
result.append( l->lcblk->dump(" ") );
sp<const Buffer> buf0(l->getBuffer(0));
sp<const Buffer> buf1(l->getBuffer(1));
@@ -1539,10 +1540,10 @@
snprintf(buffer, SIZE,
" "
"format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
- " freezeLock=%p\n",
+ " freezeLock=%p, dq-q-time=%u us\n",
l->pixelFormat(),
w0, h0, s0, w1, h1, s1,
- l->getFreezeLock().get());
+ l->getFreezeLock().get(), stats.totalTime);
result.append(buffer);
buffer[0] = 0;
}
diff --git a/libs/ui/SharedBufferStack.cpp b/libs/ui/SharedBufferStack.cpp
index 7789a3f..9ad4349 100644
--- a/libs/ui/SharedBufferStack.cpp
+++ b/libs/ui/SharedBufferStack.cpp
@@ -276,6 +276,8 @@
LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
tail, stack.head, stack.available, stack.queued);
}
+
+ const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
//LOGD("[%d] about to dequeue a buffer",
// mSharedStack->identity);
@@ -296,6 +298,8 @@
LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s",
dequeued, tail, dump("").string());
+ mDequeueTime[dequeued] = dequeueTime;
+
return dequeued;
}
@@ -312,7 +316,7 @@
status_t SharedBufferClient::lock(int buf)
{
LockCondition condition(this, buf);
- status_t err = waitForCondition(condition);
+ status_t err = waitForCondition(condition);
return err;
}
@@ -321,6 +325,9 @@
QueueUpdate update(this);
status_t err = updateCondition( update );
LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
+ SharedBufferStack& stack( *mSharedStack );
+ const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
+ stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
return err;
}
@@ -393,5 +400,12 @@
return stack.getDirtyRegion(buffer);
}
+SharedBufferStack::Statistics SharedBufferServer::getStats() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.stats;
+}
+
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index ba4c4c7..c4c6149 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1148,6 +1148,13 @@
CODEC_LOGV("Finished flushing both ports, now continuing from"
" seek-time.");
+ // Clear this flag in case the decoder sent us either
+ // the EVENT_BUFFER_FLAG(1) or an output buffer with
+ // the EOS flag set _while_ flushing. Since we're going
+ // to submit "fresh" input data now, this flag no longer
+ // applies to our future.
+ mNoMoreOutputData = false;
+
drainInputBuffers();
fillOutputBuffers();
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
index 69e93a1..10796f1 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
@@ -16,6 +16,7 @@
package com.android.mediaframeworktest.stress;
+
import com.android.mediaframeworktest.MediaFrameworkTest;
import java.io.BufferedWriter;
@@ -26,6 +27,7 @@
import android.hardware.Camera;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
+import android.os.Looper;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
@@ -54,7 +56,14 @@
private static final String OUTPUT_FILE_EXT = ".3gp";
private static final String MEDIA_STRESS_OUTPUT =
"/sdcard/mediaStressOutput.txt";
-
+ private Looper mCameraLooper = null;
+ private Looper mRecorderLooper = null;
+ private final Object lock = new Object();
+ private final Object recorderlock = new Object();
+ private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000; // Milliseconds.
+ private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback();
+ private final RecorderErrorCallback mRecorderErrorCallback = new RecorderErrorCallback();
+
public MediaRecorderStressTest() {
super("com.android.mediaframeworktest", MediaFrameworkTest.class);
}
@@ -63,41 +72,129 @@
getActivity();
super.setUp();
}
-
+
+ private final class CameraErrorCallback implements android.hardware.Camera.ErrorCallback {
+ public void onError(int error, android.hardware.Camera camera) {
+ if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) {
+ assertTrue("Camera test mediaserver died", false);
+ }
+ }
+ }
+
+ private final class RecorderErrorCallback implements MediaRecorder.OnErrorListener {
+ public void onError(MediaRecorder mr, int what, int extra) {
+ // fail the test case no matter what error come up
+ assertTrue("mediaRecorder error", false);
+ }
+ }
+
+ private void initializeCameraMessageLooper() {
+ Log.v(TAG, "start looper");
+ new Thread() {
+ @Override
+ public void run() {
+ // Set up a looper to be used by camera.
+ Looper.prepare();
+ Log.v(TAG, "start loopRun");
+ mCameraLooper = Looper.myLooper();
+ mCamera = Camera.open();
+ synchronized (lock) {
+ lock.notify();
+ }
+ Looper.loop();
+ Log.v(TAG, "initializeMessageLooper: quit.");
+ }
+ }.start();
+ }
+
+ private void initializeRecorderMessageLooper() {
+ Log.v(TAG, "start looper");
+ new Thread() {
+ @Override
+ public void run() {
+ Looper.prepare();
+ Log.v(TAG, "start loopRun");
+ mRecorderLooper = Looper.myLooper();
+ mRecorder = new MediaRecorder();
+ synchronized (recorderlock) {
+ recorderlock.notify();
+ }
+ Looper.loop(); // Blocks forever until Looper.quit() is called.
+ Log.v(TAG, "initializeMessageLooper: quit.");
+ }
+ }.start();
+ }
+
+ /*
+ * Terminates the message looper thread.
+ */
+ private void terminateCameraMessageLooper() {
+ mCameraLooper.quit();
+ try {
+ Thread.sleep(1000);
+ } catch (Exception e){
+ Log.v(TAG, e.toString());
+ }
+ mCamera.release();
+ }
+
+ /*
+ * Terminates the message looper thread.
+ */
+ private void terminateRecorderMessageLooper() {
+ mRecorderLooper.quit();
+ try {
+ Thread.sleep(1000);
+ } catch (Exception e){
+ Log.v(TAG, e.toString());
+ }
+ mRecorder.release();
+ }
+
//Test case for stressing the camera preview.
@LargeTest
public void testStressCamera() throws Exception {
- SurfaceHolder mSurfaceHolder;
+ SurfaceHolder mSurfaceHolder;
mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
output.write("Camera start preview stress:\n");
- output.write("Total number of loops:" +
+ output.write("Total number of loops:" +
NUMBER_OF_CAMERA_STRESS_LOOPS + "\n");
- try {
+ try {
Log.v(TAG, "Start preview");
output.write("No of loop: ");
+
for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++){
- mCamera = Camera.open();
+ synchronized (lock) {
+ initializeCameraMessageLooper();
+ try {
+ lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+ } catch(Exception e) {
+ Log.v(TAG, "wait was interrupted.");
+ }
+ }
+ mCamera.setErrorCallback(mCameraErrorCallback);
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
Thread.sleep(WAIT_TIME_CAMERA_TEST);
mCamera.stopPreview();
- mCamera.release();
+ terminateCameraMessageLooper();
output.write(" ," + i);
}
} catch (Exception e) {
- Log.v(TAG, e.toString());
+ assertTrue("CameraStressTest", false);
+ Log.v(TAG, e.toString());
}
output.write("\n\n");
output.close();
}
-
+
//Test case for stressing the camera preview.
@LargeTest
public void testStressRecorder() throws Exception {
String filename;
- SurfaceHolder mSurfaceHolder;
+ SurfaceHolder mSurfaceHolder;
mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
@@ -108,12 +205,20 @@
output.write("No of loop: ");
Log.v(TAG, "Start preview");
for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++){
+ synchronized (recorderlock) {
+ initializeRecorderMessageLooper();
+ try {
+ recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+ } catch(Exception e) {
+ Log.v(TAG, "wait was interrupted.");
+ }
+ }
Log.v(TAG, "counter = " + i);
filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
Log.v(TAG, filename);
- mRecorder = new MediaRecorder();
+ mRecorder.setOnErrorListener(mRecorderErrorCallback);
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
- mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+ mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(filename);
mRecorder.setVideoFrameRate(20);
mRecorder.setVideoSize(176,144);
@@ -125,47 +230,63 @@
Log.v(TAG, "prepare");
mRecorder.prepare();
Log.v(TAG, "before release");
- Thread.sleep(WAIT_TIME_RECORDER_TEST);
+ Thread.sleep(WAIT_TIME_RECORDER_TEST);
mRecorder.reset();
- mRecorder.release();
+ terminateRecorderMessageLooper();
output.write(", " + i);
}
} catch (Exception e) {
- Log.v(TAG, e.toString());
+ assertTrue("Recorder Stress test", false);
+ Log.v(TAG, e.toString());
}
output.write("\n\n");
output.close();
}
-
-
+
//Stress test case for switching camera and video recorder preview.
@LargeTest
public void testStressCameraSwitchRecorder() throws Exception {
String filename;
- SurfaceHolder mSurfaceHolder;
+ SurfaceHolder mSurfaceHolder;
mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
output.write("Camera and video recorder preview switching\n");
output.write("Total number of loops:"
+ NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER + "\n");
- try {
+ try {
Log.v(TAG, "Start preview");
output.write("No of loop: ");
for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++){
- mCamera = Camera.open();
+ synchronized (lock) {
+ initializeCameraMessageLooper();
+ try {
+ lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+ } catch(Exception e) {
+ Log.v(TAG, "wait was interrupted.");
+ }
+ }
+ mCamera.setErrorCallback(mCameraErrorCallback);
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
Thread.sleep(WAIT_TIME_CAMERA_TEST);
mCamera.stopPreview();
- mCamera.release();
+ terminateCameraMessageLooper();
mCamera = null;
Log.v(TAG, "release camera");
filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
Log.v(TAG, filename);
- mRecorder = new MediaRecorder();
+ synchronized (recorderlock) {
+ initializeRecorderMessageLooper();
+ try {
+ recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+ } catch(Exception e) {
+ Log.v(TAG, "wait was interrupted.");
+ }
+ }
+ mRecorder.setOnErrorListener(mRecorderErrorCallback);
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
- mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+ mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(filename);
mRecorder.setVideoFrameRate(20);
mRecorder.setVideoSize(176,144);
@@ -176,23 +297,24 @@
Log.v(TAG, "prepare");
mRecorder.prepare();
Log.v(TAG, "before release");
- Thread.sleep(WAIT_TIME_CAMERA_TEST);
- mRecorder.release();
+ Thread.sleep(WAIT_TIME_CAMERA_TEST);
+ terminateRecorderMessageLooper();
Log.v(TAG, "release video recorder");
output.write(", " + i);
}
} catch (Exception e) {
+ assertTrue("Camer and recorder switch mode", false);
Log.v(TAG, e.toString());
}
output.write("\n\n");
output.close();
}
-
+
//Stress test case for record a video and play right away.
@LargeTest
public void testStressRecordVideoAndPlayback() throws Exception {
String filename;
- SurfaceHolder mSurfaceHolder;
+ SurfaceHolder mSurfaceHolder;
mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
@@ -204,10 +326,18 @@
for (int i = 0; i < NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS; i++){
filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
Log.v(TAG, filename);
- mRecorder = new MediaRecorder();
+ synchronized (recorderlock) {
+ initializeRecorderMessageLooper();
+ try {
+ recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+ } catch(Exception e) {
+ Log.v(TAG, "wait was interrupted.");
+ }
+ }
+ mRecorder.setOnErrorListener(mRecorderErrorCallback);
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
- mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+ mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(filename);
mRecorder.setVideoFrameRate(20);
mRecorder.setVideoSize(352,288);
@@ -216,11 +346,11 @@
Log.v(TAG, "mediaRecorder setPreview");
mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
mRecorder.prepare();
- mRecorder.start();
+ mRecorder.start();
Thread.sleep(WAIT_TIME_RECORD);
Log.v(TAG, "Before stop");
mRecorder.stop();
- mRecorder.release();
+ terminateRecorderMessageLooper();
//start the playback
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(filename);
@@ -232,10 +362,10 @@
output.write(", " + i);
}
} catch (Exception e) {
+ assertTrue("record and playback", false);
Log.v(TAG, e.toString());
}
output.write("\n\n");
output.close();
- }
+ }
}
-
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
index 705794a..d4887ba 100644
--- a/opengl/tests/gl2_basic/gl2_basic.cpp
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -33,27 +33,72 @@
static void printGLString(const char *name, GLenum s)
{
+ fprintf(stderr, "printGLString %s, %d\n", name, s);
+#if 0 // causes hangs
const char *v = (const char *)glGetString(s);
- if (v)
- printf("GL %s = %s\n", name, v);
+ int error = glGetError();
+ fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error,
+ (unsigned int)v);
+ if ((v < (const char*) 0) || (v > (const char*) 0x10000))
+ fprintf(stderr, "GL %s = %s\n", name, v);
else
- printf("GL %s = (null)\n", name);
+ fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v);
+#endif
+}
+
+static const char* eglErrorToString[] = {
+ "EGL_SUCCESS", // 0x3000 12288
+ "EGL_NOT_INITIALIZED",
+ "EGL_BAD_ACCESS", // 0x3002 12290
+ "EGL_BAD_ALLOC",
+ "EGL_BAD_ATTRIBUTE",
+ "EGL_BAD_CONFIG",
+ "EGL_BAD_CONTEXT", // 0x3006 12294
+ "EGL_BAD_CURRENT_SURFACE",
+ "EGL_BAD_DISPLAY",
+ "EGL_BAD_MATCH",
+ "EGL_BAD_NATIVE_PIXMAP",
+ "EGL_BAD_NATIVE_WINDOW",
+ "EGL_BAD_PARAMETER", // 0x300c 12300
+ "EGL_BAD_SURFACE"
+};
+
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+ if (returnVal != EGL_TRUE) {
+ fprintf(stderr, "%s() returned %d\n", op, returnVal);
+ }
+
+ for(EGLint error = eglGetError();
+ error != EGL_SUCCESS;
+ error = eglGetError()) {
+ const char* errorString = "unknown";
+ if (error >= EGL_SUCCESS && error <= EGL_BAD_SURFACE) {
+ errorString = eglErrorToString[error - EGL_SUCCESS];
+ }
+ fprintf(stderr, "after %s() eglError %s (0x%x)\n", op,
+ errorString, error);
+ }
}
int main(int argc, char** argv)
{
+ EGLBoolean returnValue;
+ EGLConfig configs[2];
+ EGLint config_count;
+
+ EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
EGLint s_configAttribs[] = {
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_NONE
+ EGL_BUFFER_SIZE, EGL_DONT_CARE,
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_DEPTH_SIZE, 8,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
};
- EGLint numConfigs = -1;
EGLint majorVersion;
EGLint minorVersion;
- EGLConfig config;
EGLContext context;
EGLSurface surface;
EGLint w, h;
@@ -63,19 +108,63 @@
EGLNativeWindowType window = 0;
window = android_createDisplaySurface();
+ checkEglError("<init>");
dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(dpy, &majorVersion, &minorVersion);
+ checkEglError("eglGetDisplay");
+ if (dpy == EGL_NO_DISPLAY) {
+ printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
+ return 0;
+ }
+ returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+ checkEglError("eglInitialize", returnValue);
+ fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
+
+ returnValue = eglGetConfigs (dpy, configs, 2, &config_count);
+ checkEglError("eglGetConfigs", returnValue);
+ fprintf(stderr, "Config count: %d\n", config_count);
+ for(int i = 0; i < config_count; i++) {
+ fprintf(stderr, "%d: 0x%08x\n", i, (unsigned int) configs[i]);
+ }
+#if 0
+ EGLConfig config;
EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &config);
- surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ checkEglError("EGLUtils::selectConfigForNativeWindow");
+#else
+ int chooseConfigResult = eglChooseConfig(dpy, s_configAttribs, configs, 2, &config_count);
+ checkEglError("eglChooseConfig", chooseConfigResult);
+ if (chooseConfigResult != EGL_TRUE )
+ {
+ printf("eglChooseConfig failed\n");
+ return 0;
+ }
+#endif
- EGLint gl2_0Attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+ surface = eglCreateWindowSurface(dpy, configs[0], window, NULL);
+ checkEglError("eglCreateWindowSurface");
+ if (surface == EGL_NO_SURFACE)
+ {
+ printf("gelCreateWindowSurface failed.\n");
+ return 0;
+ }
+ EGLint gl2_0Attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
- context = eglCreateContext(dpy, config, NULL, gl2_0Attribs);
+ context = eglCreateContext(dpy, configs[0], EGL_NO_CONTEXT, context_attribs);
+ checkEglError("eglCreateContext");
+ if (context == EGL_NO_CONTEXT)
+ {
+ printf("eglCreateContext failed\n");
+ return 0;
+ }
eglMakeCurrent(dpy, surface, surface, context);
+ checkEglError("eglMakeCurrent");
eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ checkEglError("eglQuerySurface");
eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ checkEglError("eglQuerySurface");
GLint dim = w<h ? w : h;
+ fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
+
printGLString("Version", GL_VERSION);
printGLString("Vendor", GL_VENDOR);
printGLString("Renderer", GL_RENDERER);
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 0e60dd6..c6be61d 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -649,11 +649,21 @@
int N = packages.size();
for (int a = N-1; a >= 0; a--) {
PackageInfo pkg = packages.get(a);
- ApplicationInfo app = pkg.applicationInfo;
- if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
- || app.backupAgentName == null
- || (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
- pkg.packageName) != PackageManager.PERMISSION_GRANTED)) {
+ try {
+ ApplicationInfo app = pkg.applicationInfo;
+ if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
+ || app.backupAgentName == null
+ || (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
+ pkg.packageName) != PackageManager.PERMISSION_GRANTED)) {
+ packages.remove(a);
+ }
+ else {
+ // we will need the shared library path, so look that up and store it here
+ app = mPackageManager.getApplicationInfo(pkg.packageName,
+ PackageManager.GET_SHARED_LIBRARY_FILES);
+ pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
+ }
+ } catch (NameNotFoundException e) {
packages.remove(a);
}
}
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 30c25e0..60195b9 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
@@ -111,6 +112,30 @@
Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
mContext.sendStickyBroadcast(intent);
+
+ // Launch a dock activity
+ String category;
+ switch (mDockState) {
+ case Intent.EXTRA_DOCK_STATE_CAR:
+ category = Intent.CATEGORY_CAR_DOCK;
+ break;
+ case Intent.EXTRA_DOCK_STATE_DESK:
+ category = Intent.CATEGORY_DESK_DOCK;
+ break;
+ default:
+ category = null;
+ break;
+ }
+ if (category != null) {
+ intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(category);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, e.getCause());
+ }
+ }
}
}
};
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index af60556..f6a1be7 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -1069,13 +1069,13 @@
return mIntent;
}
- boolean isInProximity(double latitude, double longitude) {
+ boolean isInProximity(double latitude, double longitude, float accuracy) {
Location loc = new Location("");
loc.setLatitude(latitude);
loc.setLongitude(longitude);
double radius = loc.distanceTo(mLocation);
- return radius <= mRadius;
+ return radius <= Math.max(mRadius,accuracy);
}
@Override
@@ -1115,6 +1115,7 @@
long now = System.currentTimeMillis();
double latitude = loc.getLatitude();
double longitude = loc.getLongitude();
+ float accuracy = loc.getAccuracy();
ArrayList<PendingIntent> intentsToRemove = null;
for (ProximityAlert alert : mProximityAlerts.values()) {
@@ -1124,7 +1125,7 @@
if ((expiration == -1) || (now <= expiration)) {
boolean entered = mProximitiesEntered.contains(alert);
boolean inProximity =
- alert.isInProximity(latitude, longitude);
+ alert.isInProximity(latitude, longitude, accuracy);
if (!entered && inProximity) {
if (LOCAL_LOGV) {
Log.v(TAG, "Entered alert");
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 35f508b8..84250bc 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -957,9 +957,6 @@
private void sendNotificationLocked(boolean on, int why)
{
- if (mProximitySensorActive) {
- why = WindowManagerPolicy.OFF_BECAUSE_OF_PROXIMITY_SENSOR;
- }
if (!on) {
mStillNeedSleepNotification = false;
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 60496d6..d53f002 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -7056,7 +7056,7 @@
+ " attHidden=" + mAttachedHidden
+ " tok.hiddenRequested="
+ (mAppToken != null ? mAppToken.hiddenRequested : false)
- + " tok.idden="
+ + " tok.hidden="
+ (mAppToken != null ? mAppToken.hidden : false)
+ " animating=" + mAnimating
+ " tok animating="
@@ -7085,10 +7085,20 @@
if (mAttrs.type != TYPE_APPLICATION_STARTING
&& mAppToken != null) {
mAppToken.firstWindowDrawn = true;
- if (mAnimation == null && mAppToken.startingData != null) {
+
+ if (mAppToken.startingData != null) {
if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
+ mToken
+ ": first real window is shown, no animation");
+ // If this initial window is animating, stop it -- we
+ // will do an animation to reveal it from behind the
+ // starting window, so there is no need for it to also
+ // be doing its own stuff.
+ if (mAnimation != null) {
+ mAnimation = null;
+ // Make sure we clean up the animation.
+ mAnimating = true;
+ }
mFinishedStarting.add(mAppToken);
mH.sendEmptyMessage(H.FINISHED_STARTING);
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 4368464..2672c6d 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -129,6 +129,8 @@
return uri.getSchemeSpecificPart();
}
+ // TODO: We don't check for SecurityException here (requires
+ // READ_PHONE_STATE permission).
if (scheme.equals("voicemail")) {
return TelephonyManager.getDefault().getVoiceMailNumber();
}
@@ -1179,6 +1181,35 @@
}
/**
+ * isVoiceMailNumber: checks a given number against the voicemail
+ * number provided by the RIL and SIM card. The caller must have
+ * the READ_PHONE_STATE credential.
+ *
+ * @param number the number to look up.
+ * @return true if the number is in the list of voicemail. False
+ * otherwise, including if the caller does not have the permission
+ * to read the VM number.
+ * @hide TODO: pending API Council approval
+ */
+ public static boolean isVoiceMailNumber(String number) {
+ String vmNumber;
+
+ try {
+ vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+ } catch (SecurityException ex) {
+ return false;
+ }
+
+ // Strip the separators from the number before comparing it
+ // to the list.
+ number = extractNetworkPortion(number);
+
+ // compare tolerates null so we need to make sure that we
+ // don't return true when both are null.
+ return !TextUtils.isEmpty(number) && compare(number, vmNumber);
+ }
+
+ /**
* Translates any alphabetic letters (i.e. [A-Za-z]) in the
* specified phone number into the equivalent numeric digits,
* according to the phone keypad letter mapping described in
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index c8490e9..01b1746 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -101,13 +101,12 @@
public boolean isCachedPhotoCurrent;
private boolean mIsEmergency;
-
- // Don't keep checking VM if it's going to throw an exception for this proc.
- private static boolean sSkipVmCheck = false;
+ private boolean mIsVoiceMail;
public CallerInfo() {
// TODO: Move all the basic initialization here?
mIsEmergency = false;
+ mIsVoiceMail = false;
}
/**
@@ -220,32 +219,15 @@
public static CallerInfo getCallerInfo(Context context, String number) {
if (TextUtils.isEmpty(number)) {
return null;
- } else {
- // Change the callerInfo number ONLY if it is an emergency number
- // or if it is the voicemail number. If it is either, take a
- // shortcut and skip the query.
- if (PhoneNumberUtils.isEmergencyNumber(number)) {
- return new CallerInfo().markAsEmergency(context);
- } else {
- try {
- if (!sSkipVmCheck && PhoneNumberUtils.compare(number,
- TelephonyManager.getDefault().getVoiceMailNumber())) {
- CallerInfo ci = new CallerInfo();
+ }
- // Note we're setting the phone number here (refer to javadoc
- // comments at the top of CallerInfo class).
- ci.phoneNumber = TelephonyManager.getDefault().getVoiceMailAlphaTag();
- // TODO: FIND ANOTHER ICON
- //info.photoResource = android.R.drawable.badge_voicemail;
- return ci;
- }
- } catch (SecurityException ex) {
- // Don't crash if this process doesn't have permission to
- // retrieve VM number. It's still allowed to look up caller info.
- // But don't try it again.
- sSkipVmCheck = true;
- }
- }
+ // Change the callerInfo number ONLY if it is an emergency number
+ // or if it is the voicemail number. If it is either, take a
+ // shortcut and skip the query.
+ if (PhoneNumberUtils.isEmergencyNumber(number)) {
+ return new CallerInfo().markAsEmergency(context);
+ } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+ return new CallerInfo().markAsVoiceMail();
}
Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
@@ -304,6 +286,13 @@
}
/**
+ * @return true if the caller info is a voicemail number.
+ */
+ public boolean isVoiceMailNumber() {
+ return mIsVoiceMail;
+ }
+
+ /**
* Mark this CallerInfo as an emergency call.
* @param context To lookup the localized 'Emergency Number' string.
* @return this instance.
@@ -323,6 +312,37 @@
return this;
}
+
+ /**
+ * Mark this CallerInfo as a voicemail call. The voicemail label
+ * is obtained from the telephony manager. Caller must hold the
+ * READ_PHONE_STATE permission otherwise the phoneNumber will be
+ * set to null.
+ * @return this instance.
+ */
+ // TODO: As in the emergency number handling, we end up writing a
+ // string in the phone number field.
+ /* package */ CallerInfo markAsVoiceMail() {
+ mIsVoiceMail = true;
+
+ try {
+ String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag();
+
+ phoneNumber = voiceMailLabel;
+ } catch (SecurityException se) {
+ // Should never happen: if this process does not have
+ // permission to retrieve VM tag, it should not have
+ // permission to retrieve VM number and would not call
+ // this method.
+ // Leave phoneNumber untouched.
+ Log.e(TAG, "Cannot access VoiceMail.", se);
+ }
+ // TODO: There is no voicemail picture?
+ // FIXME: FIND ANOTHER ICON
+ // photoResource = android.R.drawable.badge_voicemail;
+ return this;
+ }
+
private static String normalize(String s) {
if (s == null || s.length() > 0) {
return s;
@@ -330,4 +350,31 @@
return null;
}
}
+
+ /**
+ * @return a string debug representation of this instance.
+ */
+ public String toString() {
+ return new StringBuilder(384)
+ .append("\nname: " + name)
+ .append("\nphoneNumber: " + phoneNumber)
+ .append("\ncnapName: " + cnapName)
+ .append("\nnumberPresentation: " + numberPresentation)
+ .append("\nnamePresentation: " + namePresentation)
+ .append("\ncontactExits: " + contactExists)
+ .append("\nphoneLabel: " + phoneLabel)
+ .append("\nnumberType: " + numberType)
+ .append("\nnumberLabel: " + numberLabel)
+ .append("\nphotoResource: " + photoResource)
+ .append("\nperson_id: " + person_id)
+ .append("\nneedUpdate: " + needUpdate)
+ .append("\ncontactRefUri: " + contactRefUri)
+ .append("\ncontactRingtoneUri: " + contactRefUri)
+ .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
+ .append("\ncachedPhoto: " + cachedPhoto)
+ .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
+ .append("\nemergency: " + mIsEmergency)
+ .append("\nvoicemail " + mIsVoiceMail)
+ .toString();
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 4227a84..802e79b 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -47,9 +47,6 @@
private CallerInfoAsyncQueryHandler mHandler;
- // Don't keep checking VM if it's going to throw an exception for this proc.
- private static boolean sSkipVmCheck = false;
-
/**
* Interface for a CallerInfoAsyncQueryHandler result return.
*/
@@ -227,18 +224,7 @@
// comments at the top of CallerInfo class).
mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext);
} else if (cw.event == EVENT_VOICEMAIL_NUMBER) {
- mCallerInfo = new CallerInfo();
- try {
- // Note we're setting the phone number here (refer to javadoc
- // comments at the top of CallerInfo class).
- mCallerInfo.phoneNumber =
- TelephonyManager.getDefault().getVoiceMailAlphaTag();
- } catch (SecurityException ex) {
- // Should never happen: if this process does not have
- // permission to retrieve VM tag, it should not have
- // permission to retrieve VM number and would not generate
- // an EVENT_VOICEMAIL_NUMBER. But if it happens, don't crash.
- }
+ mCallerInfo = new CallerInfo().markAsVoiceMail();
} else {
mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor);
// Use the number entered by the user for display.
@@ -258,7 +244,7 @@
//notify the listener that the query is complete.
if (cw.listener != null) {
if (DBG) log("notifying listener: " + cw.listener.getClass().toString() +
- " for token: " + token);
+ " for token: " + token + mCallerInfo);
cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
}
}
@@ -315,23 +301,10 @@
// check to see if these are recognized numbers, and use shortcuts if we can.
if (PhoneNumberUtils.isEmergencyNumber(number)) {
cw.event = EVENT_EMERGENCY_NUMBER;
+ } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+ cw.event = EVENT_VOICEMAIL_NUMBER;
} else {
- String vmNumber = null;
- if (!sSkipVmCheck){
- try {
- vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
- } catch (SecurityException ex) {
- // Don't crash if this process doesn't have permission to
- // retrieve VM number. It's still allowed to look up caller info.
- // But don't try it again.
- sSkipVmCheck = true;
- }
- }
- if (PhoneNumberUtils.compare(number, vmNumber)) {
- cw.event = EVENT_VOICEMAIL_NUMBER;
- } else {
- cw.event = EVENT_NEW_QUERY;
- }
+ cw.event = EVENT_NEW_QUERY;
}
c.mHandler.startQuery (token, cw, contactRef, null, null, null, null);
diff --git a/telephony/tests/TelephonyTest/AndroidManifest.xml b/telephony/tests/TelephonyTest/AndroidManifest.xml
index c0cc0d5..b2a481b 100644
--- a/telephony/tests/TelephonyTest/AndroidManifest.xml
+++ b/telephony/tests/TelephonyTest/AndroidManifest.xml
@@ -28,8 +28,9 @@
</intent-filter>
</activity>
</application>
- <instrumentation android:name=".TelephonyUnitTestRunner"
- android:targetPackage="com.android.telephonytest"
- android:label="Telephony unit tests InstrumentationRunner">
- </instrumentation>
+ <instrumentation android:name=".TelephonyUnitTestRunner"
+ android:targetPackage="com.android.telephonytest"
+ android:label="Telephony unit tests InstrumentationRunner">
+ </instrumentation>
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
</manifest>
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
index 5da940d..9e1af31 100644
--- a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
@@ -37,6 +37,7 @@
public TestSuite getAllTests() {
TestSuite suite = new InstrumentationTestSuite(this);
suite.addTestSuite(com.android.telephonytest.unit.CallerInfoUnitTest.class);
+ suite.addTestSuite(com.android.telephonytest.unit.PhoneNumberUtilsUnitTest.class);
return suite;
}
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
index 4cd0266..0f24f15 100644
--- a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
@@ -107,6 +107,16 @@
assertIsValidEmergencyCallerInfo();
}
+ // TODO: Add more tests:
+ /**
+ * Check if the voice mail number cannot be retrieved that the
+ * original phone number is preserved.
+ */
+ /**
+ * Check the markAs* methods work.
+ */
+
+
//
// Helpers
//
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java
new file mode 100644
index 0000000..2d3c548
--- /dev/null
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telephonytest.unit;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+
+/*
+ * Check the PhoneNumberUtils utility class works as expected.
+ *
+ */
+
+public class PhoneNumberUtilsUnitTest extends AndroidTestCase {
+ private String mVoiceMailNumber;
+ private static final String TAG = "PhoneNumberUtilsUnitTest";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // FIXME: Why are we getting a security exception here? The
+ // permission is declared in the manifest....
+ // mVoiceMailNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Basic checks for the VoiceMail number.
+ * Assumes READ_PHONE_STATE permission and we don't have it.
+ */
+ // TODO: Figure out why we don't have the permission declared in the manifest.
+ @SmallTest
+ public void testWithNumberNotEqualToVoiceMail() throws Exception {
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber("911"));
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber("tel:911"));
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber("+18001234567"));
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber(""));
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber(null));
+ // FIXME:
+ // assertTrue(PhoneNumberUtils.isVoiceMailNumber(mVoiceMailNumber));
+ }
+
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
index c62f94f..f2025c6 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
@@ -36,8 +36,11 @@
public void testHandlerThread() throws Exception {
HandlerThread th1 = new HandlerThread("HandlerThreadTest") {
protected void onLooperPrepared() {
- mDidSetup = true;
- mLooperTid = Process.myTid();
+ synchronized (HandlerThreadTest.this) {
+ mDidSetup = true;
+ mLooperTid = Process.myTid();
+ HandlerThreadTest.this.notify();
+ }
}
};
@@ -49,14 +52,23 @@
assertTrue(th1.isAlive());
assertNotNull(th1.getLooper());
- /*
- * Since getLooper() will block until the HandlerThread is setup, we are guaranteed
- * that mDidSetup and mLooperTid will have been initalized. If they have not, then
- * this test should fail
- */
+ // The call to getLooper() internally blocks until the looper is
+ // available, but will call onLooperPrepared() after that. So we
+ // need to block here to wait for our onLooperPrepared() to complete
+ // and fill in the values we expect.
+ synchronized (this) {
+ while (!mDidSetup) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ // Make sure that the process was set.
+ assertNotSame(-1, mLooperTid);
// Make sure that the onLooperPrepared() was called on a different thread.
assertNotSame(Process.myTid(), mLooperTid);
- assertTrue(mDidSetup);
final Handler h1 = new Handler(th1.getLooper()) {
public void handleMessage(Message msg) {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 8fea967..395e572 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -96,7 +96,9 @@
// Android layout tests are stored in "layout_tests". The following two
// tests expect "LayoutTests" in their output.
"storage/domstorage/localstorage/iframe-events.html",
- "storage/domstorage/sessionstorage/iframe-events.html"
+ "storage/domstorage/sessionstorage/iframe-events.html",
+ // below tests (failed or crashes) are filtered out temporarily due to prioritizing
+ "editing/selection/move-left-right.html",
};
static void fillIgnoreResultSet() {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
index cc2f1f5..85e0422 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
@@ -1,5 +1,23 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.dumprendertree;
+import com.android.dumprendertree.forwarder.ForwardService;
+
import android.util.Log;
import java.io.BufferedOutputStream;
@@ -12,6 +30,12 @@
public class FsUtils {
private static final String LOGTAG = "FsUtils";
+ static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/";
+ static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/";
+ static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/";
+ static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/";
+ static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/";
+
private FsUtils() {
//no creation of instances
}
@@ -77,4 +101,24 @@
return status;
}
+ public static String getTestUrl(String path) {
+ String url = null;
+ if (!path.startsWith(HTTP_TESTS_PREFIX)) {
+ url = "file://" + path;
+ } else {
+ ForwardService.getForwardService().startForwardService();
+ if (path.startsWith(HTTPS_TESTS_PREFIX)) {
+ // still cut the URL after "http/tests/"
+ url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
+ && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
+ && !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
+ url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else {
+ url = "file://" + path;
+ }
+ }
+ return url;
+ }
+
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index e4c8716..235e10e 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -19,6 +19,7 @@
import com.android.dumprendertree.TestShellActivity.DumpDataType;
import com.android.dumprendertree.forwarder.AdbUtils;
import com.android.dumprendertree.forwarder.ForwardServer;
+import com.android.dumprendertree.forwarder.ForwardService;
import android.app.Instrumentation;
import android.content.Intent;
@@ -143,17 +144,6 @@
static final String LAYOUT_RESULTS_CRASHED_RESULT_FILE = "results/layout_tests_crashed.txt";
static final String LAYOUT_TESTS_RUNNER = "run_layout_tests.py";
- static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/";
- static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/";
- static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/";
- static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/";
- static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/";
-
-
- static final String DEFAULT_TEST_HOST = "android-browser-test.mtv.corp.google.com";
- static final String FORWARD_HOST_CONF = "/sdcard/drt_forward_host.txt";
- private ForwardServer fs8000, fs8080, fs8443;
-
private MyTestRecorder mResultRecorder;
private Vector<String> mTestList;
private boolean mRebaselineResults;
@@ -162,45 +152,6 @@
public LayoutTestsAutoTest() {
super("com.android.dumprendertree", TestShellActivity.class);
-
- int addr = getForwardHostAddr();
- if(addr != -1) {
- fs8000 = new ForwardServer(8000, addr, 8000);
- fs8080 = new ForwardServer(8080, addr, 8080);
- fs8443 = new ForwardServer(8443, addr, 8443);
- }
- }
-
- private int getForwardHostAddr() {
- int addr = -1;
- String host = null;
- File forwardHostConf = new File(FORWARD_HOST_CONF);
- if (forwardHostConf.isFile()) {
- BufferedReader hostReader = null;
- try {
- hostReader = new BufferedReader(new FileReader(forwardHostConf));
- host = hostReader.readLine();
- Log.v(LOGTAG, "read forward host from file: " + host);
- } catch (IOException ioe) {
- Log.v(LOGTAG, "cannot read forward host from file", ioe);
- } finally {
- if (hostReader != null) {
- try {
- hostReader.close();
- } catch (IOException ioe) {
- // burn!!!
- }
- }
- }
- }
- if (host == null || host.length() == 0)
- host = DEFAULT_TEST_HOST;
- try {
- addr = AdbUtils.resolve(host);
- } catch (IOException ioe) {
- Log.e(LOGTAG, "failed to resolve server address", ioe);
- }
- return addr;
}
// This function writes the result of the layout test to
@@ -366,7 +317,7 @@
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(activity, TestShellActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- intent.putExtra(TestShellActivity.TEST_URL, getTestUrl(test));
+ intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(test));
intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
activity.startActivity(intent);
@@ -450,49 +401,10 @@
}
FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE");
- if(fs8000 != null)
- fs8000.stop();
- if(fs8080 != null)
- fs8080.stop();
- if(fs8443 != null)
- fs8443.stop();
-
+ ForwardService.getForwardService().stopForwardService();
activity.finish();
}
- private void startForwardServerIfNeeded() {
- try {
- if(fs8000 != null)
- fs8000.start();
- if(fs8080 != null)
- fs8080.start();
- if(fs8443 != null)
- fs8443.start();
- } catch (IOException ioe) {
- Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe);
- }
- }
-
- private String getTestUrl(String path) {
- String url = null;
- if (!path.startsWith(HTTP_TESTS_PREFIX)) {
- url = "file://" + path;
- } else {
- startForwardServerIfNeeded();
- if (path.startsWith(HTTPS_TESTS_PREFIX)) {
- // still cut the URL after "http/tests/"
- url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length());
- } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
- && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
- && !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
- url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
- } else {
- url = "file://" + path;
- }
- }
- return url;
- }
-
private String getTestPath() {
LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
index 71d9758..50b7c3f 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.dumprendertree;
import android.app.Activity;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
index 995c129..fbce78a 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.dumprendertree;
import android.app.Activity;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 663df83..3fef61c 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -16,6 +16,8 @@
package com.android.dumprendertree;
+import com.android.dumprendertree.forwarder.ForwardService;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
@@ -184,6 +186,7 @@
} catch (IOException ioe) {
Log.w(LOGTAG, "Failed to close test list file.", ioe);
}
+ ForwardService.getForwardService().stopForwardService();
finished();
}
@@ -215,10 +218,9 @@
builder.create().show();
return;
}
- url = "file://" + url;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- intent.putExtra(TestShellActivity.TEST_URL, url);
+ intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(url));
intent.putExtra(TIMEOUT_IN_MILLIS, 10000);
executeIntent(intent);
}
@@ -289,13 +291,20 @@
}
public void finished() {
- if (mUiAutoTestPath != null) {
- //don't really finish here
- moveToNextTest();
- } else {
- if (mCallback != null) {
- mCallback.finished();
+ if (mTestPageLoaded) {
+ if (mUiAutoTestPath != null) {
+ //don't really finish here
+ moveToNextTest();
+ } else {
+ if (mCallback != null) {
+ mCallback.finished();
+ }
}
+ } else {
+ // The test is complete but the page has not completed loading. We
+ // can't continue to the next test until both the test is finished
+ // and the page has stopped loading.
+ mReadyForNextTest = true;
}
}
@@ -443,12 +452,14 @@
@Override
public void onPageFinished(WebView view, String url) {
Log.v(LOGTAG, "onPageFinished, url=" + url);
+ mTestPageLoaded = true;
super.onPageFinished(view, url);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.v(LOGTAG, "onPageStarted, url=" + url);
+ mTestPageLoaded = false;
super.onPageStarted(view, url, favicon);
}
@@ -478,6 +489,17 @@
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress == 100) {
+
+ if (mReadyForNextTest) {
+ // In this case, the test has completed (i.e. called
+ // layoutTestController.notifyDone) before the page finished loading. This
+ // usually happens if the test is not invoked by an onload handler, rather
+ // directly in a script tag. Now that the page has finished loading, it is
+ // safe for DRT to go to the next test.
+ finished();
+ return;
+ }
+
if (!mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) {
String url = mWebView.getUrl();
Log.v(LOGTAG, "Finished: "+ url);
@@ -653,6 +675,8 @@
mDumpDatabaseCallbacks = false;
mCanOpenWindows = false;
mEventSender.resetMouse();
+ mTestPageLoaded = false;
+ mReadyForNextTest = false;
}
private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) {
@@ -709,6 +733,9 @@
private StringBuffer mConsoleMessages;
private boolean mCanOpenWindows;
+ private boolean mTestPageLoaded = false;
+ private boolean mReadyForNextTest = false;
+
static final String TIMEOUT_STR = "**Test timeout";
static final int MSG_TIMEOUT = 0;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
index 9a3e9c2..c2ecf3a 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.dumprendertree.forwarder;
import android.util.Log;
@@ -44,7 +60,6 @@
DataInputStream dis = new DataInputStream(localSocket.getInputStream());
OutputStream os = localSocket.getOutputStream();
int count_read = 0;
- byte[] buf = new byte[128];
if (localSocket == null || dis == null || os == null)
return -1;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
index 74e018e..14f8fbe 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.dumprendertree.forwarder;
import android.util.Log;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
new file mode 100644
index 0000000..8b7de6e
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree.forwarder;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+import android.util.Log;
+
+public class ForwardService {
+
+ private ForwardServer fs8000, fs8080, fs8443;
+
+ private static ForwardService inst;
+
+ private static final String LOGTAG = "ForwardService";
+
+ private static final String DEFAULT_TEST_HOST = "android-browser-test.mtv.corp.google.com";
+
+ private static final String FORWARD_HOST_CONF = "/sdcard/drt_forward_host.txt";
+
+ private ForwardService() {
+ int addr = getForwardHostAddr();
+ if (addr != -1) {
+ fs8000 = new ForwardServer(8000, addr, 8000);
+ fs8080 = new ForwardServer(8080, addr, 8080);
+ fs8443 = new ForwardServer(8443, addr, 8443);
+ }
+ }
+
+ public static ForwardService getForwardService() {
+ if (inst == null) {
+ inst = new ForwardService();
+ }
+ return inst;
+ }
+
+ public void startForwardService() {
+ try {
+ if (fs8000 != null)
+ fs8000.start();
+ if (fs8080 != null)
+ fs8080.start();
+ if (fs8443 != null)
+ fs8443.start();
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe);
+ return;
+ }
+ }
+
+ public void stopForwardService() {
+ if (fs8000 != null) {
+ fs8000.stop();
+ fs8000 = null;
+ }
+ if (fs8080 != null) {
+ fs8080.stop();
+ fs8080 = null;
+ }
+ if (fs8443 != null) {
+ fs8443.stop();
+ fs8443 = null;
+ }
+ Log.v(LOGTAG, "forwarders stopped.");
+ }
+
+ private static int getForwardHostAddr() {
+ int addr = -1;
+ String host = null;
+ File forwardHostConf = new File(FORWARD_HOST_CONF);
+ if (forwardHostConf.isFile()) {
+ BufferedReader hostReader = null;
+ try {
+ hostReader = new BufferedReader(new FileReader(forwardHostConf));
+ host = hostReader.readLine();
+ Log.v(LOGTAG, "read forward host from file: " + host);
+ } catch (IOException ioe) {
+ Log.v(LOGTAG, "cannot read forward host from file", ioe);
+ } finally {
+ if (hostReader != null) {
+ try {
+ hostReader.close();
+ } catch (IOException ioe) {
+ // burn!!!
+ }
+ }
+ }
+ }
+ if (host == null || host.length() == 0)
+ host = DEFAULT_TEST_HOST;
+ try {
+ addr = AdbUtils.resolve(host);
+ } catch (IOException ioe) {
+ Log.e(LOGTAG, "failed to resolve server address", ioe);
+ }
+ return addr;
+ }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
index e1e04a7..a1f3cdf 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.dumprendertree.forwarder;
import android.util.Log;
diff --git a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
index dc959f5..aea124b 100644
--- a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
+++ b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
@@ -29,7 +29,6 @@
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
-import java.util.Hashtable;
import java.util.Set;
import java.util.Map;
import java.util.Map.Entry;
@@ -145,7 +144,7 @@
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Return cursor over specific set of values
- return getCursor(sTestValues1);
+ return getCursor(sTestValues1, 1);
}
}, null, 0);
} catch (OperationApplicationException e) {
@@ -153,11 +152,62 @@
}
}
+ public void testAssertNoValues() {
+ // Build an operation to assert values match provider
+ ContentProviderOperation op1 = ContentProviderOperation.newAssertQuery(sTestUri1)
+ .withExpectedCount(1).build();
+
+ try {
+ // Assert that values match from cursor
+ ContentProviderResult result = op1.apply(new TestContentProvider() {
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ // Return cursor over specific set of values
+ return getCursor(sTestValues1, 1);
+ }
+ }, null, 0);
+ } catch (OperationApplicationException e) {
+ fail("newAssert() failed");
+ }
+
+ ContentProviderOperation op2 = ContentProviderOperation.newAssertQuery(sTestUri1)
+ .withExpectedCount(0).build();
+
+ try {
+ // Assert that values match from cursor
+ ContentProviderResult result = op2.apply(new TestContentProvider() {
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ // Return cursor over specific set of values
+ return getCursor(sTestValues1, 0);
+ }
+ }, null, 0);
+ } catch (OperationApplicationException e) {
+ fail("newAssert() failed");
+ }
+
+ ContentProviderOperation op3 = ContentProviderOperation.newAssertQuery(sTestUri1)
+ .withExpectedCount(2).build();
+
+ try {
+ // Assert that values match from cursor
+ ContentProviderResult result = op3.apply(new TestContentProvider() {
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ // Return cursor over specific set of values
+ return getCursor(sTestValues1, 5);
+ }
+ }, null, 0);
+ fail("we expect the exception to be thrown");
+ } catch (OperationApplicationException e) {
+ }
+ }
+
/**
* Build a {@link Cursor} with a single row that contains all values
* provided through the given {@link ContentValues}.
*/
- private Cursor getCursor(ContentValues contentValues) {
+ private Cursor getCursor(ContentValues contentValues, int numRows) {
final Set<Entry<String, Object>> valueSet = contentValues.valueSet();
final String[] keys = new String[valueSet.size()];
final Object[] values = new Object[valueSet.size()];
@@ -170,7 +220,9 @@
}
final MatrixCursor cursor = new MatrixCursor(keys);
- cursor.addRow(values);
+ for (i = 0; i < numRows; i++) {
+ cursor.addRow(values);
+ }
return cursor;
}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 9a11404..e3d8bf4 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -1350,7 +1350,7 @@
*/
private synchronized void requestPolledInfo(WifiInfo info, boolean polling)
{
- int newRssi = WifiNative.getRssiCommand();
+ int newRssi = (polling ? WifiNative.getRssiApproxCommand() : WifiNative.getRssiCommand());
if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
/* some implementations avoid negative values by adding 256
* so we need to adjust for that here.