From 15ab3eae2ec3d73b3e8aa60b33ae41445bf83f4b Mon Sep 17 00:00:00 2001
From: The Android Open Source Project
Date: Fri, 20 Feb 2009 07:38:31 -0800
Subject: [PATCH] auto import from //branches/cupcake/...@132569
---
api/current.xml | 22 +
core/java/android/app/Activity.java | 13 +-
core/java/android/hardware/SensorManager.java | 18 +
.../inputmethodservice/SoftInputWindow.java | 3 +-
core/java/android/preference/Preference.java | 7 -
.../android/preference/PreferenceScreen.java | 1 -
core/java/android/provider/Checkin.java | 5 +
core/java/android/provider/Gmail.java | 10 +
core/java/android/provider/MediaStore.java | 6 +
.../server/BluetoothDeviceService.java | 21 +-
.../android/server/BluetoothEventLoop.java | 3 +-
core/java/android/view/KeyEvent.java | 4 +-
.../view/OrientationEventListener.java | 20 +-
core/java/android/view/SurfaceHolder.java | 2 +-
core/java/android/view/ViewRoot.java | 11 +-
.../android/view/WindowManagerPolicy.java | 17 +-
.../view/WindowOrientationListener.java | 20 +-
core/java/android/webkit/WebSettings.java | 6 +
core/java/android/webkit/WebView.java | 116 ++++-
core/java/android/webkit/WebViewCore.java | 9 +-
.../webkit/gears/GearsPluginSettings.java | 95 ----
.../webkit/gears/HtmlDialogAndroid.java | 174 -------
.../webkit/gears/IGearsDialogService.java | 107 ----
core/java/android/widget/Adapter.java | 2 +-
core/java/android/widget/TextView.java | 16 +-
core/java/android/widget/ZoomRing.java | 113 ++--
.../android/widget/ZoomRingController.java | 82 ++-
.../internal/widget/TextProgressBar.java | 1 +
.../android/util/GoogleWebContentHelper.java | 2 +-
core/res/res/color/tertiary_text_dark.xml | 2 +-
core/res/res/drawable/sym_action_add.png | Bin 0 -> 930 bytes
.../res/drawable/zoom_ring_track_absolute.png | Bin 16759 -> 19660 bytes
.../google_web_content_helper_layout.xml | 2 +-
core/res/res/values/attrs.xml | 1 +
include/ui/KeycodeLabels.h | 4 +-
media/libmedia/AudioRecord.cpp | 2 +-
media/libmedia/ToneGenerator.cpp | 19 +-
.../functional/MediaAudioTrackTest.java | 125 ++++-
.../functional/TonesAutoTest.java | 2 +-
.../MediaRecorderPrepareStateUnitTest.java | 2 +-
...diaRecorderSetOutputFileStateUnitTest.java | 20 +-
.../MediaRecorderStateUnitTestTemplate.java | 7 +
.../android/server/PowerManagerService.java | 54 +-
.../android/server/WindowManagerService.java | 17 +-
.../internal/telephony/WapPushOverSms.java | 211 ++++++++
.../internal/telephony/WspTypeDecoder.java | 344 +++++++++++++
.../internal/telephony/gsm/SMSDispatcher.java | 157 +-----
.../telephony/gsm/ServiceStateTracker.java | 83 +--
tests/AndroidTests/AndroidManifest.xml | 2 -
.../com/android/unit_tests/BluetoothTest.java | 484 ------------------
tools/aapt/Package.cpp | 10 +
wifi/java/android/net/wifi/WifiMonitor.java | 64 +--
52 files changed, 1255 insertions(+), 1263 deletions(-)
delete mode 100644 core/java/android/webkit/gears/GearsPluginSettings.java
delete mode 100644 core/java/android/webkit/gears/HtmlDialogAndroid.java
delete mode 100644 core/java/android/webkit/gears/IGearsDialogService.java
create mode 100644 core/res/res/drawable/sym_action_add.png
create mode 100644 telephony/java/com/android/internal/telephony/WapPushOverSms.java
create mode 100644 telephony/java/com/android/internal/telephony/WspTypeDecoder.java
delete mode 100644 tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java
diff --git a/api/current.xml b/api/current.xml
index aa6471b7bbc26..9ccb8f7945ecb 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -118963,6 +118963,17 @@
visibility="public"
>
+
+
+
+
Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
@@ -907,9 +907,9 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Called after {@link #onStart} when the current activity is being
+ * Called after {@link #onStop} when the current activity is being
* re-displayed to the user (the user has navigated back to it). It will
- * be followed by {@link #onResume}.
+ * be followed by {@link #onStart} and then {@link #onResume}.
*
* For activities that are using raw {@link Cursor} objects (instead of
* creating them through
@@ -923,6 +923,7 @@ public class Activity extends ContextThemeWrapper
* thrown.
*
* @see #onStop
+ * @see #onStart
* @see #onResume
*/
protected void onRestart() {
@@ -1220,7 +1221,7 @@ public class Activity extends ContextThemeWrapper
/**
* Called when you are no longer visible to the user. You will next
- * receive either {@link #onStart}, {@link #onDestroy}, or nothing,
+ * receive either {@link #onRestart}, {@link #onDestroy}, or nothing,
* depending on later user activity.
*
* Note that this method may never be called, in low memory situations
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 3981f2784ef40..e232c2cee0435 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -620,6 +620,9 @@ public class SensorManager extends IRotationWatcher.Stub
*/
@Deprecated
public boolean registerListener(SensorListener listener, int sensors, int rate) {
+ if (listener == null) {
+ return false;
+ }
boolean result = false;
result = registerLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
listener, sensors, rate) || result;
@@ -638,6 +641,9 @@ public class SensorManager extends IRotationWatcher.Stub
private boolean registerLegacyListener(int legacyType, int type,
SensorListener listener, int sensors, int rate)
{
+ if (listener == null) {
+ return false;
+ }
boolean result = false;
// Are we activating this legacy sensor?
if ((sensors & legacyType) != 0) {
@@ -693,6 +699,9 @@ public class SensorManager extends IRotationWatcher.Stub
private void unregisterLegacyListener(int legacyType, int type,
SensorListener listener, int sensors)
{
+ if (listener == null) {
+ return;
+ }
// do we know about this listener?
LegacyListener legacyListener = null;
synchronized (mLegacyListenersMap) {
@@ -800,6 +809,9 @@ public class SensorManager extends IRotationWatcher.Stub
*/
public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate,
Handler handler) {
+ if (listener == null || sensor == null) {
+ return false;
+ }
boolean result;
int delay = -1;
switch (rate) {
@@ -856,6 +868,9 @@ public class SensorManager extends IRotationWatcher.Stub
}
private void unregisterListener(Object listener, Sensor sensor) {
+ if (listener == null || sensor == null) {
+ return;
+ }
try {
synchronized (sListeners) {
final int size = sListeners.size();
@@ -881,6 +896,9 @@ public class SensorManager extends IRotationWatcher.Stub
}
private void unregisterListener(Object listener) {
+ if (listener == null) {
+ return;
+ }
try {
synchronized (sListeners) {
final int size = sListeners.size();
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index da67c6d168a6e..c37845f02b632 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -141,7 +141,8 @@ class SoftInputWindow extends Dialog {
lp.gravity = Gravity.BOTTOM;
lp.width = -1;
// Let the input method window's orientation follow sensor based rotation
- lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
+ // Turn this off for now, it is very problematic.
+ //lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
getWindow().setAttributes(lp);
getWindow().setFlags(
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 3820f28563262..a2554388651ad 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -667,7 +667,6 @@ public class Preference implements Comparable, OnDependencyChangeLis
* {@link SharedPreferences}. This should be unique for the package.
*
* @param key The key for the preference.
- * @see #getId()
*/
public void setKey(String key) {
mKey = key;
@@ -1460,7 +1459,6 @@ public class Preference implements Comparable, OnDependencyChangeLis
* @param container The Bundle in which to save the instance of this Preference.
*
* @see #restoreHierarchyState
- * @see #dispatchSaveInstanceState
* @see #onSaveInstanceState
*/
public void saveHierarchyState(Bundle container) {
@@ -1474,7 +1472,6 @@ public class Preference implements Comparable, OnDependencyChangeLis
*
* @param container The Bundle in which to save the instance of this Preference.
*
- * @see #dispatchRestoreInstanceState
* @see #saveHierarchyState
* @see #onSaveInstanceState
*/
@@ -1503,7 +1500,6 @@ public class Preference implements Comparable, OnDependencyChangeLis
* The default implementation returns null.
* @see #onRestoreInstanceState
* @see #saveHierarchyState
- * @see #dispatchSaveInstanceState
*/
protected Parcelable onSaveInstanceState() {
mBaseMethodCalled = true;
@@ -1516,7 +1512,6 @@ public class Preference implements Comparable, OnDependencyChangeLis
* @param container The Bundle that holds the previously saved state.
*
* @see #saveHierarchyState
- * @see #dispatchRestoreInstanceState
* @see #onRestoreInstanceState
*/
public void restoreHierarchyState(Bundle container) {
@@ -1530,7 +1525,6 @@ public class Preference implements Comparable, OnDependencyChangeLis
* not want to save state for their children.
*
* @param container The Bundle that holds the previously saved state.
- * @see #dispatchSaveInstanceState
* @see #restoreHierarchyState
* @see #onRestoreInstanceState
*/
@@ -1557,7 +1551,6 @@ public class Preference implements Comparable, OnDependencyChangeLis
* {@link #onSaveInstanceState}.
* @see #onSaveInstanceState
* @see #restoreHierarchyState
- * @see #dispatchRestoreInstanceState
*/
protected void onRestoreInstanceState(Parcelable state) {
mBaseMethodCalled = true;
diff --git a/core/java/android/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java
index 9929b963755e0..5353b531dd068 100644
--- a/core/java/android/preference/PreferenceScreen.java
+++ b/core/java/android/preference/PreferenceScreen.java
@@ -100,7 +100,6 @@ public final class PreferenceScreen extends PreferenceGroup implements AdapterVi
*
* @return An adapter that provides the {@link Preference} contained in this
* {@link PreferenceScreen}.
- * @see PreferenceGroupAdapter
*/
public ListAdapter getRootAdapter() {
if (mRootAdapter == null) {
diff --git a/core/java/android/provider/Checkin.java b/core/java/android/provider/Checkin.java
index 688e19a83c76d..0cdac53525bd8 100644
--- a/core/java/android/provider/Checkin.java
+++ b/core/java/android/provider/Checkin.java
@@ -126,6 +126,11 @@ public final class Checkin {
/** Valid tag values. Extend as necessary for your needs. */
public enum Tag {
+ BROWSER_SNAP_CENTER,
+ BROWSER_TEXT_SIZE_CHANGE,
+ BROWSER_ZOOM_OVERVIEW,
+ BROWSER_ZOOM_RING,
+ BROWSER_ZOOM_RING_DRAG,
CRASHES_REPORTED,
CRASHES_TRUNCATED,
ELAPSED_REALTIME_SEC,
diff --git a/core/java/android/provider/Gmail.java b/core/java/android/provider/Gmail.java
index 253dd4a6d22e1..5b3c2234ded1c 100644
--- a/core/java/android/provider/Gmail.java
+++ b/core/java/android/provider/Gmail.java
@@ -1477,10 +1477,20 @@ public final class Gmail {
LABEL_OUTBOX, LABEL_DRAFT, LABEL_ALL,
LABEL_SPAM, LABEL_TRASH);
+
+ private static final Set USER_MEANINGFUL_SYSTEM_LABELS_SET =
+ Sets.newHashSet(
+ SORTED_USER_MEANINGFUL_SYSTEM_LABELS.toArray(
+ new String[]{}));
+
public static List getSortedUserMeaningfulSystemLabels() {
return SORTED_USER_MEANINGFUL_SYSTEM_LABELS;
}
+ public static Set getUserMeaningfulSystemLabelsSet() {
+ return USER_MEANINGFUL_SYSTEM_LABELS_SET;
+ }
+
/**
* If you are ever tempted to remove outbox or draft from this set make sure you have a
* way to stop draft and outbox messages from getting purged before they are sent to the
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 2897b4e7645d8..b91bc9d56f2af 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -157,6 +157,12 @@ public final class MediaStore
*/
public final static String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality";
+ /**
+ * Specify the maximum allowed size.
+ * @hide
+ */
+ public final static String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit";
+
/**
* The name of the Intent-extra used to indicate a content resolver Uri to be used to
* store the requested image or video.
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
index 86d5a1e73bd35..fa53a601077e2 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothDeviceService.java
@@ -47,8 +47,8 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
public class BluetoothDeviceService extends IBluetoothDevice.Stub {
@@ -121,7 +121,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
* Bring down bluetooth. Returns true on success.
*
* @param saveSetting If true, disable BT in settings
- *
+ *
*/
public synchronized boolean disable(boolean saveSetting) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
@@ -172,7 +172,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
* This turns on/off the underlying hardware.
*
* @param saveSetting If true, enable BT in settings
- *
+ *
* @return True on success (so far), guaranteeing the callback with be
* notified when complete.
*/
@@ -275,6 +275,14 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
private final HashMap mState = new HashMap();
private final HashMap mPinAttempt = new HashMap();
private final ArrayList mAutoPairingFailures = new ArrayList();
+ // List of all the vendor_id prefix of Bluetooth addresses for which
+ // auto pairing is not attempted
+ private final ArrayList mAutoPairingBlacklisted =
+ new ArrayList(Arrays.asList(
+ "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", //ALPS
+ "00:21:4F", "00:23:06", "00:24:33", "00:A0:79", // ALPS
+ "00:0E:6D", "00:13:E0", "00:21:E8", "00:60:57"// Murata for Prius 2007
+ ));
public synchronized void loadBondState() {
if (!mIsEnabled) {
@@ -322,6 +330,13 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
+ public boolean isAutoPairingBlacklisted(String address) {
+ for (String blacklistAddress : mAutoPairingBlacklisted) {
+ if (address.startsWith(blacklistAddress)) return true;
+ }
+ return false;
+ }
+
public synchronized int getBondState(String address) {
Integer state = mState.get(address);
if (state == null) {
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 187ec2cf3a0b3..8b09583492d4b 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -312,7 +312,8 @@ class BluetoothEventLoop {
case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
- if (!mBluetoothService.getBondState().hasAutoPairingFailed(address)) {
+ if (!mBluetoothService.getBondState().hasAutoPairingFailed(address) &&
+ !mBluetoothService.getBondState().isAutoPairingBlacklisted(address)) {
mBluetoothService.getBondState().attempt(address);
mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
return;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index d5434b6a1a8bb..d6ea91c4b5e37 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -117,7 +117,8 @@ public class KeyEvent implements Parcelable {
public static final int KEYCODE_PREVIOUSSONG = 88;
public static final int KEYCODE_REWIND = 89;
public static final int KEYCODE_FORWARD = 90;
- private static final int LAST_KEYCODE = KEYCODE_FORWARD;
+ public static final int KEYCODE_MUTE = 91;
+ private static final int LAST_KEYCODE = KEYCODE_MUTE;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
@@ -502,6 +503,7 @@ public class KeyEvent implements Parcelable {
case KEYCODE_ENDCALL:
case KEYCODE_VOLUME_UP:
case KEYCODE_VOLUME_DOWN:
+ case KEYCODE_MUTE:
case KEYCODE_POWER:
case KEYCODE_HEADSETHOOK:
case KEYCODE_PLAYPAUSE:
diff --git a/core/java/android/view/OrientationEventListener.java b/core/java/android/view/OrientationEventListener.java
index cddec11a35638..391ba1e794c30 100755
--- a/core/java/android/view/OrientationEventListener.java
+++ b/core/java/android/view/OrientationEventListener.java
@@ -69,8 +69,11 @@ public abstract class OrientationEventListener {
public OrientationEventListener(Context context, int rate) {
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
mRate = rate;
- mSensorEventListener = new SensorEventListenerImpl();
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ if (mSensor != null) {
+ // Create listener only if sensors do exist
+ mSensorEventListener = new SensorEventListenerImpl();
+ }
}
void registerListener(OrientationListener lis) {
@@ -82,6 +85,10 @@ public abstract class OrientationEventListener {
* {@link #onOrientationChanged} when the device orientation changes.
*/
public void enable() {
+ if (mSensor == null) {
+ Log.w(TAG, "Cannot detect sensors. Not enabled");
+ return;
+ }
if (mEnabled == false) {
if (localLOGV) Log.d(TAG, "OrientationEventListener enabled");
mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
@@ -93,6 +100,10 @@ public abstract class OrientationEventListener {
* Disables the OrientationEventListener.
*/
public void disable() {
+ if (mSensor == null) {
+ Log.w(TAG, "Cannot detect sensors. Invalid disable");
+ return;
+ }
if (mEnabled == true) {
if (localLOGV) Log.d(TAG, "OrientationEventListener disabled");
mSensorManager.unregisterListener(mSensorEventListener);
@@ -138,6 +149,13 @@ public abstract class OrientationEventListener {
}
}
+
+ /*
+ * Returns true if sensor is enabled and false otherwise
+ */
+ public boolean canDetectOrientation() {
+ return mSensor != null;
+ }
/**
* Called when the orientation of the device has changed.
diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java
index 21a72e7184fe7..3d0dda3db48be 100644
--- a/core/java/android/view/SurfaceHolder.java
+++ b/core/java/android/view/SurfaceHolder.java
@@ -240,7 +240,7 @@ public interface SurfaceHolder {
* in particular there is no guarantee that the content of the Surface
* will remain unchanged when lockCanvas() is called again.
*
- * @see android.view.SurfaceHolder.lockCanvas
+ * @see #lockCanvas()
*
* @param canvas The Canvas previously returned by lockCanvas().
*/
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index db8829f9bc027..3cfaf1b4c27cf 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1817,6 +1817,11 @@ public final class ViewRoot extends Handler implements ViewParent,
if (event != null) {
event.recycle();
}
+ // If we reach this, we delivered a trackball event to mView and
+ // mView consumed it. Because we will not translate the trackball
+ // event into a key event, touch mode will not exit, so we exit
+ // touch mode here.
+ ensureTouchMode(false);
//noinspection ReturnInsideFinallyBlock
return;
}
@@ -2140,7 +2145,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
boolean keyHandled = mView.dispatchKeyEvent(event);
- if ((!keyHandled && isDown) || (action == KeyEvent.ACTION_MULTIPLE)) {
+ if (!keyHandled && isDown) {
int direction = 0;
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_LEFT:
@@ -2541,7 +2546,7 @@ public final class ViewRoot extends Handler implements ViewParent,
* for us to consider the user to be doing fast trackball movements,
* and thus apply an acceleration.
*/
- static final long FAST_MOVE_TIME = 100;
+ static final long FAST_MOVE_TIME = 150;
/**
* Scaling factor to the time (in milliseconds) between events to how
@@ -2549,7 +2554,7 @@ public final class ViewRoot extends Handler implements ViewParent,
* is < FAST_MOVE_TIME this multiplies the acceleration; when >
* FAST_MOVE_TIME it divides it.
*/
- static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/50);
+ static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
float position;
float absPosition;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 051f823fdfdea..0f15b176344f2 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -129,13 +129,21 @@ public interface WindowManagerPolicy {
Rect contentFrame, Rect visibleFrame);
/**
- * Retrieve the current frame of the window. Must be called with the
- * window manager lock held.
+ * Retrieve the current frame of the window that has been assigned by
+ * the window manager. Must be called with the window manager lock held.
*
* @return Rect The rectangle holding the window frame.
*/
public Rect getFrameLw();
+ /**
+ * Retrieve the current frame of the window that is actually shown.
+ * Must be called with the window manager lock held.
+ *
+ * @return Rect The rectangle holding the shown window frame.
+ */
+ public Rect getShownFrameLw();
+
/**
* Retrieve the frame of the display that this window was last
* laid out in. Must be called with the
@@ -273,9 +281,12 @@ public interface WindowManagerPolicy {
* false, this is based on the currently requested
* frame, which any current animation will be moving
* towards.
+ * @param onlyOpaque If true, this will only pass if the window is
+ * also opaque.
* @return Returns true if the window is both full screen and opaque
*/
- public boolean fillsScreenLw(int width, int height, boolean shownFrame);
+ public boolean fillsScreenLw(int width, int height, boolean shownFrame,
+ boolean onlyOpaque);
/**
* Returns true if this window has been shown on screen at some time in
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 4aa3f7aa783bc..58779321f79a0 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -74,8 +74,11 @@ public abstract class WindowOrientationListener {
public WindowOrientationListener(Context context, int rate) {
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
mRate = rate;
- mSensorEventListener = new SensorEventListenerImpl();
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ if (mSensor != null) {
+ // Create listener only if sensors do exist
+ mSensorEventListener = new SensorEventListenerImpl();
+ }
}
/**
@@ -83,6 +86,10 @@ public abstract class WindowOrientationListener {
* {@link #onOrientationChanged} when the device orientation changes.
*/
public void enable() {
+ if (mSensor == null) {
+ Log.w(TAG, "Cannot detect sensors. Not enabled");
+ return;
+ }
if (mEnabled == false) {
if (localLOGV) Log.d(TAG, "WindowOrientationListener enabled");
mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
@@ -94,6 +101,10 @@ public abstract class WindowOrientationListener {
* Disables the WindowOrientationListener.
*/
public void disable() {
+ if (mSensor == null) {
+ Log.w(TAG, "Cannot detect sensors. Invalid disable");
+ return;
+ }
if (mEnabled == true) {
if (localLOGV) Log.d(TAG, "WindowOrientationListener disabled");
mSensorManager.unregisterListener(mSensorEventListener);
@@ -145,6 +156,13 @@ public abstract class WindowOrientationListener {
}
}
+ /*
+ * Returns true if sensor is enabled and false otherwise
+ */
+ public boolean canDetectOrientation() {
+ return mSensor != null;
+ }
+
/**
* Called when the orientation of the device has changed.
* orientation parameter is in degrees, ranging from 0 to 359.
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 5c470cf1bf15f..4e2b2ab6df393 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -20,6 +20,8 @@ import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
+import android.provider.Checkin;
+
import java.lang.SecurityException;
import android.content.pm.PackageManager;
@@ -408,6 +410,10 @@ public class WebSettings {
* @see WebSettings.TextSize
*/
public synchronized void setTextSize(TextSize t) {
+ if (WebView.mLogEvent && mTextSize != t ) {
+ Checkin.updateStats(mContext.getContentResolver(),
+ Checkin.Stats.Tag.BROWSER_TEXT_SIZE_CHANGE, 1, 0.0);
+ }
mTextSize = t;
postSync();
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4d9a8fbafda55..c59a5fcfbf8d7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -38,11 +38,13 @@ import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.provider.Checkin;
import android.text.IClipboard;
import android.text.Selection;
import android.text.Spannable;
import android.util.AttributeSet;
import android.util.Config;
+import android.util.EventLog;
import android.util.Log;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
@@ -450,6 +452,13 @@ public class WebView extends AbsoluteLayout
// Used to match key downs and key ups
private boolean mGotKeyDown;
+ /* package */ static boolean mLogEvent = true;
+ private static final int EVENT_LOG_ZOOM_LEVEL_CHANGE = 70101;
+ private static final int EVENT_LOG_DOUBLE_TAP_DURATION = 70102;
+
+ // for event log
+ private long mLastTouchUpTime = 0;
+
/**
* URI scheme for telephone number
*/
@@ -556,7 +565,11 @@ public class WebView extends AbsoluteLayout
private ZoomRingController.OnZoomListener mZoomListener =
new ZoomRingController.OnZoomListener() {
-
+
+ private float mClockwiseBound;
+ private float mCounterClockwiseBound;
+ private float mStartScale;
+
public void onCenter(int x, int y) {
// Don't translate when the control is invoked, hence we do nothing
// in this callback
@@ -564,6 +577,10 @@ public class WebView extends AbsoluteLayout
public void onBeginPan() {
setZoomOverviewVisible(false);
+ if (mLogEvent) {
+ Checkin.updateStats(mContext.getContentResolver(),
+ Checkin.Stats.Tag.BROWSER_ZOOM_RING_DRAG, 1, 0.0);
+ }
}
public boolean onPan(int deltaX, int deltaY) {
@@ -576,12 +593,25 @@ public class WebView extends AbsoluteLayout
public void onVisibilityChanged(boolean visible) {
if (visible) {
switchOutDrawHistory();
+ if (mMaxZoomScale - 1 > ZOOM_RING_STEPS * 0.01f) {
+ mClockwiseBound = (float) (2 * Math.PI - MAX_ZOOM_RING_ANGLE);
+ } else {
+ mClockwiseBound = (float) (2 * Math.PI);
+ }
+ mZoomRingController.setThumbClockwiseBound(mClockwiseBound);
+ if (1 - mMinZoomScale > ZOOM_RING_STEPS * 0.01f) {
+ mCounterClockwiseBound = MAX_ZOOM_RING_ANGLE;
+ } else {
+ mCounterClockwiseBound = 0;
+ }
+ mZoomRingController
+ .setThumbCounterclockwiseBound(mCounterClockwiseBound);
float angle = 0f;
- if (mActualScale > 1) {
+ if (mActualScale > 1 && mClockwiseBound < (float) (2 * Math.PI)) {
angle = -(float) Math.round(ZOOM_RING_STEPS
* (mActualScale - 1) / (mMaxZoomScale - 1))
/ ZOOM_RING_STEPS;
- } else if (mActualScale < 1) {
+ } else if (mActualScale < 1 && mCounterClockwiseBound > 0) {
angle = (float) Math.round(ZOOM_RING_STEPS
* (1 - mActualScale) / (1 - mMinZoomScale))
/ ZOOM_RING_STEPS;
@@ -590,16 +620,26 @@ public class WebView extends AbsoluteLayout
// Show the zoom overview tab on the ring
setZoomOverviewVisible(true);
+ if (mLogEvent) {
+ Checkin.updateStats(mContext.getContentResolver(),
+ Checkin.Stats.Tag.BROWSER_ZOOM_RING, 1, 0.0);
+ }
}
}
public void onBeginDrag() {
mPreviewZoomOnly = true;
+ mStartScale = mActualScale;
setZoomOverviewVisible(false);
}
public void onEndDrag() {
mPreviewZoomOnly = false;
+ if (mLogEvent) {
+ EventLog.writeEvent(EVENT_LOG_ZOOM_LEVEL_CHANGE,
+ (int) mStartScale * 100, (int) mActualScale * 100,
+ System.currentTimeMillis());
+ }
setNewZoomScale(mActualScale, true);
}
@@ -616,21 +656,21 @@ public class WebView extends AbsoluteLayout
mZoomCenterY = (float) centerY;
float scale = 1.0f;
- if (curAngle > (float) Math.PI)
- curAngle -= (float) 2 * Math.PI;
- if (curAngle > 0) {
- if (curAngle >= MAX_ZOOM_RING_ANGLE) {
+ // curAngle is [0, 2 * Math.PI)
+ if (curAngle < (float) Math.PI) {
+ if (curAngle >= mCounterClockwiseBound) {
scale = mMinZoomScale;
} else {
scale = 1 - (float) Math.round(curAngle
/ ZOOM_RING_ANGLE_UNIT) / ZOOM_RING_STEPS
* (1 - mMinZoomScale);
}
- } else if (curAngle < 0) {
- if (curAngle <= -MAX_ZOOM_RING_ANGLE) {
+ } else {
+ if (curAngle <= mClockwiseBound) {
scale = mMaxZoomScale;
} else {
- scale = 1 + (float) Math.round(-curAngle
+ scale = 1 + (float) Math.round(
+ ((float) 2 * Math.PI - curAngle)
/ ZOOM_RING_ANGLE_UNIT) / ZOOM_RING_STEPS
* (mMaxZoomScale - 1);
}
@@ -687,12 +727,11 @@ public class WebView extends AbsoluteLayout
mScroller = new Scroller(context);
mZoomRingController = new ZoomRingController(context, this);
mZoomRingController.setResetThumbAutomatically(false);
- mZoomRingController.setThumbClockwiseBound(
- (float) (2 * Math.PI - MAX_ZOOM_RING_ANGLE));
- mZoomRingController.setThumbCounterclockwiseBound(MAX_ZOOM_RING_ANGLE);
mZoomRingController.setCallback(mZoomListener);
mZoomRingController.setZoomRingTrack(
com.android.internal.R.drawable.zoom_ring_track_absolute);
+ mZoomRingController.setPannerAcceleration(160);
+ mZoomRingController.setPannerStartAcceleratingDuration(700);
createZoomRingOverviewTab();
}
@@ -730,6 +769,10 @@ public class WebView extends AbsoluteLayout
public void onClick(View v) {
// Hide the zoom ring
mZoomRingController.setVisible(false);
+ if (mLogEvent) {
+ Checkin.updateStats(mContext.getContentResolver(),
+ Checkin.Stats.Tag.BROWSER_ZOOM_OVERVIEW, 1, 0.0);
+ }
zoomScrollOut();
}});
@@ -3468,7 +3511,7 @@ public class WebView extends AbsoluteLayout
// update mMinZoomScale
if (mMinContentWidth > MAX_FLOAT_CONTENT_WIDTH) {
boolean atMin = Math.abs(mActualScale - mMinZoomScale) < 0.01f;
- mMinZoomScale = (float) getViewWidth() / mMinContentWidth;
+ mMinZoomScale = (float) getViewWidth() / mContentWidth;
if (atMin) {
// if the WebView was at the minimum zoom scale, keep it. e,g.,
// the WebView was at the minimum zoom scale at the portrait
@@ -3535,7 +3578,8 @@ public class WebView extends AbsoluteLayout
return false;
}
- if (mShowZoomRingTutorial && mMinZoomScale < mMaxZoomScale) {
+ if (mShowZoomRingTutorial && getSettings().supportZoom()
+ && (mMaxZoomScale - mMinZoomScale) > ZOOM_RING_STEPS * 0.01f) {
ZoomRingController.showZoomTutorialOnce(mContext);
mShowZoomRingTutorial = false;
mPrivateHandler.sendMessageDelayed(mPrivateHandler
@@ -3616,10 +3660,18 @@ public class WebView extends AbsoluteLayout
mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
mZoomRingController.setVisible(true);
mInZoomTapDragMode = true;
+ if (mLogEvent) {
+ EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION,
+ (eventTime - mLastTouchUpTime), eventTime);
+ }
return mZoomRingController.handleDoubleTapEvent(ev);
} else {
mTouchMode = TOUCH_INIT_MODE;
mPreventDrag = mForwardTouchEvents;
+ if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
+ EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION,
+ (eventTime - mLastTouchUpTime), eventTime);
+ }
}
// don't trigger the link if zoom ring is visible
if (mTouchMode == TOUCH_INIT_MODE
@@ -3783,17 +3835,23 @@ public class WebView extends AbsoluteLayout
break;
}
case MotionEvent.ACTION_UP: {
+ mLastTouchUpTime = eventTime;
switch (mTouchMode) {
case TOUCH_INIT_MODE: // tap
if (mZoomRingController.isVisible()) {
- // don't trigger the link if zoom ring is visible
+ // don't trigger the link if zoom ring is visible,
+ // but still allow the double tap
+ mPrivateHandler.sendMessageDelayed(mPrivateHandler
+ .obtainMessage(RELEASE_SINGLE_TAP,
+ new Boolean(false)),
+ DOUBLE_TAP_TIMEOUT);
break;
}
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
- if (getSettings().supportZoom()
- && (mMinZoomScale < mMaxZoomScale)) {
+ if (getSettings().supportZoom()) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(RELEASE_SINGLE_TAP),
+ .obtainMessage(RELEASE_SINGLE_TAP,
+ new Boolean(true)),
DOUBLE_TAP_TIMEOUT);
} else {
// do short press now
@@ -3841,7 +3899,8 @@ public class WebView extends AbsoluteLayout
// as tap instead of short press.
mTouchMode = TOUCH_INIT_MODE;
mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(RELEASE_SINGLE_TAP),
+ .obtainMessage(RELEASE_SINGLE_TAP,
+ new Boolean(true)),
DOUBLE_TAP_TIMEOUT);
} else {
mTouchMode = TOUCH_DONE_MODE;
@@ -3963,6 +4022,7 @@ public class WebView extends AbsoluteLayout
+ " time=" + time
+ " mLastFocusTime=" + mLastFocusTime);
}
+ if (isInTouchMode()) requestFocusFromTouch();
return false; // let common code in onKeyDown at it
}
if (ev.getAction() == MotionEvent.ACTION_UP) {
@@ -4399,7 +4459,12 @@ public class WebView extends AbsoluteLayout
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
int contentSize = ViewConfiguration.get(getContext()).getScaledTouchSlop();
- nativeMotionUp(contentX, contentY, contentSize, true);
+ if (nativeMotionUp(contentX, contentY, contentSize, true)) {
+ if (mLogEvent) {
+ Checkin.updateStats(mContext.getContentResolver(),
+ Checkin.Stats.Tag.BROWSER_SNAP_CENTER, 1, 0.0);
+ }
+ }
if (nativeUpdateFocusNode() && !mFocusNode.mIsTextField
&& !mFocusNode.mIsTextArea) {
playSoundEffect(SoundEffectConstants.CLICK);
@@ -4619,7 +4684,9 @@ public class WebView extends AbsoluteLayout
}
case RELEASE_SINGLE_TAP: {
mTouchMode = TOUCH_DONE_MODE;
- doShortPress();
+ if ((Boolean)msg.obj) {
+ doShortPress();
+ }
break;
}
case SWITCH_TO_ENTER:
@@ -4671,7 +4738,7 @@ public class WebView extends AbsoluteLayout
mMinContentWidth = msg.arg1;
if (mMinContentWidth > MAX_FLOAT_CONTENT_WIDTH) {
mMinZoomScale = (float) getViewWidth()
- / mMinContentWidth;
+ / draw.mWidthHeight.x;
}
// We update the layout (i.e. request a layout from the
// view system) if the last view size that we sent to
@@ -5236,7 +5303,8 @@ public class WebView extends AbsoluteLayout
private native Rect nativeGetNavBounds();
private native void nativeInstrumentReport();
private native void nativeMarkNodeInvalid(int node);
- private native void nativeMotionUp(int x, int y, int slop, boolean isClick);
+ // return true if the page has been scrolled
+ private native boolean nativeMotionUp(int x, int y, int slop, boolean isClick);
// returns false if it handled the key
private native boolean nativeMoveFocus(int keyCode, int count,
boolean noScroll);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 45113ab000b7f..a7261c5ca844d 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1197,6 +1197,7 @@ final class WebViewCore {
Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
return;
}
+ // negative scale indicate that WebCore should reuse the current scale
float scale = (float) viewWidth / w;
if (mSettings.getUseWideViewPort()
&& (w < mViewportWidth || mViewportWidth == -1)) {
@@ -1224,7 +1225,7 @@ final class WebViewCore {
// keep the same width and screen width so that there is
// no reflow when zoom-out
width = minContentWidth;
- screenWidth = Math.min(screenWidth, viewWidth);
+ screenWidth = Math.min(screenWidth, Math.abs(viewWidth));
} else {
width = Math.max(w, minContentWidth);
}
@@ -1536,11 +1537,11 @@ final class WebViewCore {
// white space in the GMail which uses WebView for message view.
if (mWebView != null && mWebView.mHeightCanMeasure) {
mWebView.mLastHeightSent = 0;
- // Send a negative scale to indicate that WebCore should reuse the
- // current scale
+ // Send a negative screen width to indicate that WebCore should
+ // reuse the current scale
mEventHub.sendMessage(Message.obtain(null,
EventHub.VIEW_SIZE_CHANGED, mWebView.mLastWidthSent,
- mWebView.mLastHeightSent, new Integer(-1)));
+ mWebView.mLastHeightSent, -mWebView.mLastWidthSent));
}
mBrowserFrame.didFirstLayout();
diff --git a/core/java/android/webkit/gears/GearsPluginSettings.java b/core/java/android/webkit/gears/GearsPluginSettings.java
deleted file mode 100644
index d36d3fb2d584b..0000000000000
--- a/core/java/android/webkit/gears/GearsPluginSettings.java
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2008 The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.util.Log;
-import android.webkit.Plugin;
-import android.webkit.Plugin.PreferencesClickHandler;
-
-/**
- * Simple bridge class intercepting the click in the
- * browser plugin list and calling the Gears settings
- * dialog.
- */
-public class GearsPluginSettings {
-
- private static final String TAG = "Gears-J-GearsPluginSettings";
- private Context context;
-
- public GearsPluginSettings(Plugin plugin) {
- plugin.setClickHandler(new ClickHandler());
- }
-
- /**
- * We do not need to call the dialog synchronously here (doing so
- * actually cause a lot of problems as the main message loop is also
- * blocked), which is why we simply call it via a thread.
- */
- private class ClickHandler implements PreferencesClickHandler {
- public void handleClickEvent(Context aContext) {
- context = aContext;
- Thread startService = new Thread(new StartService());
- startService.run();
- }
- }
-
- private static native void runSettingsDialog(Context c);
-
- /**
- * StartService is the runnable we use to open the dialog.
- * We bind the service to serviceConnection; upon
- * onServiceConnected the dialog will be called from the
- * native side using the runSettingsDialog method.
- */
- private class StartService implements Runnable {
- public void run() {
- HtmlDialogAndroid.bindToService(context, serviceConnection);
- }
- }
-
- /**
- * ServiceConnection instance.
- * onServiceConnected is called upon connection with the service;
- * we can then safely open the dialog.
- */
- private ServiceConnection serviceConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- IGearsDialogService gearsDialogService =
- IGearsDialogService.Stub.asInterface(service);
- HtmlDialogAndroid.setGearsDialogService(gearsDialogService);
- runSettingsDialog(context);
- context.unbindService(serviceConnection);
- HtmlDialogAndroid.setGearsDialogService(null);
- }
- public void onServiceDisconnected(ComponentName className) {
- HtmlDialogAndroid.setGearsDialogService(null);
- }
- };
-}
diff --git a/core/java/android/webkit/gears/HtmlDialogAndroid.java b/core/java/android/webkit/gears/HtmlDialogAndroid.java
deleted file mode 100644
index 6209ab91394e1..0000000000000
--- a/core/java/android/webkit/gears/HtmlDialogAndroid.java
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2008 The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-import android.webkit.CacheManager;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-
-/**
- * Utility class to call a modal HTML dialog on Android
- */
-public class HtmlDialogAndroid {
-
- private static final String TAG = "Gears-J-HtmlDialog";
- private static final String DIALOG_PACKAGE = "com.android.browser";
- private static final String DIALOG_SERVICE = DIALOG_PACKAGE
- + ".GearsDialogService";
- private static final String DIALOG_INTERFACE = DIALOG_PACKAGE
- + ".IGearsDialogService";
-
- private static IGearsDialogService gearsDialogService;
-
- public static void setGearsDialogService(IGearsDialogService service) {
- gearsDialogService = service;
- }
-
- /**
- * Bind to the GearsDialogService.
- */
- public static boolean bindToService(Context context,
- ServiceConnection serviceConnection) {
- Intent dialogIntent = new Intent();
- dialogIntent.setClassName(DIALOG_PACKAGE, DIALOG_SERVICE);
- dialogIntent.setAction(DIALOG_INTERFACE);
- return context.bindService(dialogIntent, serviceConnection,
- Context.BIND_AUTO_CREATE);
- }
-
- /**
- * Bind to the GearsDialogService synchronously.
- * The service is started using our own defaultServiceConnection
- * handler, and we wait until the handler notifies us.
- */
- public void synchronousBindToService(Context context) {
- try {
- if (bindToService(context, defaultServiceConnection)) {
- if (gearsDialogService == null) {
- synchronized(defaultServiceConnection) {
- defaultServiceConnection.wait(3000); // timeout after 3s
- }
- }
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "exception: " + e);
- }
- }
-
- /**
- * Read the HTML content from the disk
- */
- public String readHTML(String filePath) {
- FileInputStream inputStream = null;
- String content = "";
- try {
- inputStream = new FileInputStream(filePath);
- StringBuffer out = new StringBuffer();
- byte[] buffer = new byte[4096];
- for (int n; (n = inputStream.read(buffer)) != -1;) {
- out.append(new String(buffer, 0, n));
- }
- content = out.toString();
- } catch (IOException e) {
- Log.e(TAG, "exception: " + e);
- } finally {
- if (inputStream != null) {
- try {
- inputStream.close();
- } catch (IOException e) {
- Log.e(TAG, "exception: " + e);
- }
- }
- }
- return content;
- }
-
- /**
- * Open an HTML dialog synchronously and waits for its completion.
- * The dialog is accessed through the GearsDialogService provided by
- * the Android Browser.
- * We can be called either directly, and then gearsDialogService will
- * not be set and we will bind to the service synchronously, and unbind
- * after calling the service, or called indirectly via GearsPluginSettings.
- * In the latter case, GearsPluginSettings does the binding/unbinding.
- */
- public String showDialog(Context context, String htmlFilePath,
- String arguments) {
-
- CacheManager.endCacheTransaction();
-
- String ret = null;
- boolean synchronousCall = false;
- if (gearsDialogService == null) {
- synchronousCall = true;
- synchronousBindToService(context);
- }
-
- try {
- if (gearsDialogService != null) {
- String htmlContent = readHTML(htmlFilePath);
- if (htmlContent.length() > 0) {
- ret = gearsDialogService.showDialog(htmlContent, arguments,
- !synchronousCall);
- }
- } else {
- Log.e(TAG, "Could not connect to the GearsDialogService!");
- }
- if (synchronousCall) {
- context.unbindService(defaultServiceConnection);
- gearsDialogService = null;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception: " + e);
- gearsDialogService = null;
- }
-
- CacheManager.startCacheTransaction();
-
- return ret;
- }
-
- private ServiceConnection defaultServiceConnection =
- new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- synchronized (defaultServiceConnection) {
- gearsDialogService = IGearsDialogService.Stub.asInterface(service);
- defaultServiceConnection.notify();
- }
- }
- public void onServiceDisconnected(ComponentName className) {
- gearsDialogService = null;
- }
- };
-}
diff --git a/core/java/android/webkit/gears/IGearsDialogService.java b/core/java/android/webkit/gears/IGearsDialogService.java
deleted file mode 100644
index 82a3bd97f2300..0000000000000
--- a/core/java/android/webkit/gears/IGearsDialogService.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * This file is auto-generated. DO NOT MODIFY.
- * Original file: android.webkit.gears/IGearsDialogService.aidl
- */
-package android.webkit.gears;
-import java.lang.String;
-import android.os.RemoteException;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.os.Binder;
-import android.os.Parcel;
-public interface IGearsDialogService extends android.os.IInterface
-{
-/** Local-side IPC implementation stub class. */
-public static abstract class Stub extends android.os.Binder implements android.webkit.gears.IGearsDialogService
-{
-private static final java.lang.String DESCRIPTOR = "com.android.browser.IGearsDialogService";
-/** Construct the stub at attach it to the interface. */
-public Stub()
-{
-this.attachInterface(this, DESCRIPTOR);
-}
-/**
- * Cast an IBinder object into an IGearsDialogService interface,
- * generating a proxy if needed.
- */
-public static android.webkit.gears.IGearsDialogService asInterface(android.os.IBinder obj)
-{
-if ((obj==null)) {
-return null;
-}
-android.webkit.gears.IGearsDialogService in = (android.webkit.gears.IGearsDialogService)obj.queryLocalInterface(DESCRIPTOR);
-if ((in!=null)) {
-return in;
-}
-return new android.webkit.gears.IGearsDialogService.Stub.Proxy(obj);
-}
-public android.os.IBinder asBinder()
-{
-return this;
-}
-public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
-{
-switch (code)
-{
-case INTERFACE_TRANSACTION:
-{
-reply.writeString(DESCRIPTOR);
-return true;
-}
-case TRANSACTION_showDialog:
-{
-data.enforceInterface(DESCRIPTOR);
-java.lang.String _arg0;
-_arg0 = data.readString();
-java.lang.String _arg1;
-_arg1 = data.readString();
-boolean _arg2;
-_arg2 = (0!=data.readInt());
-java.lang.String _result = this.showDialog(_arg0, _arg1, _arg2);
-reply.writeNoException();
-reply.writeString(_result);
-return true;
-}
-}
-return super.onTransact(code, data, reply, flags);
-}
-private static class Proxy implements android.webkit.gears.IGearsDialogService
-{
-private android.os.IBinder mRemote;
-Proxy(android.os.IBinder remote)
-{
-mRemote = remote;
-}
-public android.os.IBinder asBinder()
-{
-return mRemote;
-}
-public java.lang.String getInterfaceDescriptor()
-{
-return DESCRIPTOR;
-}
-public java.lang.String showDialog(java.lang.String htmlContent, java.lang.String dialogArguments, boolean inSettings) throws android.os.RemoteException
-{
-android.os.Parcel _data = android.os.Parcel.obtain();
-android.os.Parcel _reply = android.os.Parcel.obtain();
-java.lang.String _result;
-try {
-_data.writeInterfaceToken(DESCRIPTOR);
-_data.writeString(htmlContent);
-_data.writeString(dialogArguments);
-_data.writeInt(((inSettings)?(1):(0)));
-mRemote.transact(Stub.TRANSACTION_showDialog, _data, _reply, 0);
-_reply.readException();
-_result = _reply.readString();
-}
-finally {
-_reply.recycle();
-_data.recycle();
-}
-return _result;
-}
-}
-static final int TRANSACTION_showDialog = (IBinder.FIRST_CALL_TRANSACTION + 0);
-}
-public java.lang.String showDialog(java.lang.String htmlContent, java.lang.String dialogArguments, boolean inSettings) throws android.os.RemoteException;
-}
diff --git a/core/java/android/widget/Adapter.java b/core/java/android/widget/Adapter.java
index e952dd5ed0104..f2b3e2ac917fe 100644
--- a/core/java/android/widget/Adapter.java
+++ b/core/java/android/widget/Adapter.java
@@ -116,7 +116,7 @@ public interface Adapter {
* can be converted to the other in {@link #getView}. Note: Integers must be in the
* range 0 to {@link #getViewTypeCount} - 1. {@link #IGNORE_ITEM_VIEW_TYPE} can
* also be returned.
- * @see IGNORE_ITEM_VIEW_TYPE
+ * @see #IGNORE_ITEM_VIEW_TYPE
*/
int getItemViewType(int position);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index bdc54ffa02f7d..c852be5fd3631 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4132,8 +4132,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
removeParcelableSpans(content, start, end);
content.replace(start, end, text.text);
}
- Selection.setSelection((Spannable)getText(),
- text.selectionStart, text.selectionEnd);
+
+ // Now set the selection position... make sure it is in range, to
+ // avoid crashes. If this is a partial update, it is possible that
+ // the underlying text may have changed, causing us problems here.
+ // Also we just don't want to trust clients to do the right thing.
+ Spannable sp = (Spannable)getText();
+ final int N = sp.length();
+ int start = text.selectionStart;
+ if (start < 0) start = 0;
+ else if (start > N) start = N;
+ int end = text.selectionEnd;
+ if (end < 0) end = 0;
+ else if (end > N) end = N;
+ Selection.setSelection(sp, start, end);
}
/**
diff --git a/core/java/android/widget/ZoomRing.java b/core/java/android/widget/ZoomRing.java
index 22881b3bab49f..a29e1a0ec3834 100644
--- a/core/java/android/widget/ZoomRing.java
+++ b/core/java/android/widget/ZoomRing.java
@@ -84,6 +84,10 @@ public class ZoomRing extends View {
private Drawable mThumbPlusArrowDrawable;
/** Shown beneath the thumb if we can still zoom out. */
private Drawable mThumbMinusArrowDrawable;
+ private static final int THUMB_ARROW_PLUS = 1 << 0;
+ private static final int THUMB_ARROW_MINUS = 1 << 1;
+ /** Bitwise-OR of {@link #THUMB_ARROW_MINUS} and {@link #THUMB_ARROW_PLUS} */
+ private int mThumbArrowsToDraw;
private static final int THUMB_ARROWS_FADE_DURATION = 300;
private long mThumbArrowsFadeStartTime;
private int mThumbArrowsAlpha = 255;
@@ -166,7 +170,7 @@ public class ZoomRing extends View {
// TODO: add padding to drawable
setBackgroundResource(R.drawable.zoom_ring_track);
// TODO get from style
- setRingBounds(30, Integer.MAX_VALUE);
+ setRingBounds(43, Integer.MAX_VALUE);
mThumbHalfHeight = mThumbDrawable.getIntrinsicHeight() / 2;
mThumbHalfWidth = mThumbDrawable.getIntrinsicWidth() / 2;
@@ -276,7 +280,7 @@ public class ZoomRing extends View {
thumbCenterX + mThumbHalfWidth,
thumbCenterY + mThumbHalfHeight);
- if (mThumbArrowsAlpha > 0) {
+ if (mThumbArrowsToDraw > 0) {
setThumbArrowsAngle(angle);
}
@@ -420,12 +424,15 @@ public class ZoomRing extends View {
switch (action) {
case MotionEvent.ACTION_DOWN:
- mCallback.onUserInteractionStarted();
-
if (time - mPreviousUpTime <= DOUBLE_TAP_DISMISS_TIMEOUT) {
mCallback.onZoomRingDismissed(true);
+ onTouchUp(time);
+
+ // Dismissing, so halt here
+ return true;
}
+ mCallback.onUserInteractionStarted();
mPreviousDownX = x;
mPreviousDownY = y;
resetState();
@@ -441,23 +448,7 @@ public class ZoomRing extends View {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
- if (mMode == MODE_MOVE_ZOOM_RING || mMode == MODE_WAITING_FOR_MOVE_ZOOM_RING) {
- mCallback.onZoomRingSetMovableHintVisible(false);
- if (mMode == MODE_MOVE_ZOOM_RING) {
- mCallback.onZoomRingMovingStopped();
- }
- } else if (mMode == MODE_DRAG_THUMB || mMode == MODE_TAP_DRAG ||
- mMode == MODE_WAITING_FOR_DRAG_THUMB) {
- onThumbDragStopped();
-
- if (mMode == MODE_DRAG_THUMB) {
- // Animate back to a tick
- setThumbAngleAnimated(mPreviousCallbackAngle, 0);
- }
- }
-
- mPreviousUpTime = time;
- mCallback.onUserInteractionStopped();
+ onTouchUp(time);
return true;
default:
@@ -524,10 +515,9 @@ public class ZoomRing extends View {
deltaThumbAndTick = getDelta(mThumbAngle, tickAngle, !oldDirectionIsCcw);
boundAngle = getBoundIfExceeds(mThumbAngle, deltaThumbAndTick);
if (boundAngle != Integer.MIN_VALUE) {
- Log
- .d(
- TAG,
- "Tapped somewhere where the shortest distance goes through a bound, but then the opposite direction also went through a bound!");
+ // Not allowed to be here, it is between two bounds
+ mMode = MODE_IGNORE_UNTIL_UP;
+ return true;
}
}
}
@@ -574,6 +564,26 @@ public class ZoomRing extends View {
return true;
}
+
+ private void onTouchUp(long time) {
+ if (mMode == MODE_MOVE_ZOOM_RING || mMode == MODE_WAITING_FOR_MOVE_ZOOM_RING) {
+ mCallback.onZoomRingSetMovableHintVisible(false);
+ if (mMode == MODE_MOVE_ZOOM_RING) {
+ mCallback.onZoomRingMovingStopped();
+ }
+ } else if (mMode == MODE_DRAG_THUMB || mMode == MODE_TAP_DRAG ||
+ mMode == MODE_WAITING_FOR_DRAG_THUMB) {
+ onThumbDragStopped();
+
+ if (mMode == MODE_DRAG_THUMB) {
+ // Animate back to a tick
+ setThumbAngleAnimated(mPreviousCallbackAngle, 0);
+ }
+ }
+
+ mPreviousUpTime = time;
+ mCallback.onUserInteractionStopped();
+ }
private boolean isDeltaInBounds(int startAngle, int deltaAngle) {
return getBoundIfExceeds(startAngle, deltaAngle) == Integer.MIN_VALUE;
@@ -766,9 +776,11 @@ public class ZoomRing extends View {
}
}
- int deltaAngle = getDelta(mThumbAngle, touchAngle, useDirection, ccw);
- mAcculumalatedTrailAngle += Math.toDegrees(deltaAngle / (double) RADIAN_INT_MULTIPLIER);
-
+ if (DRAW_TRAIL) {
+ int deltaAngle = getDelta(mThumbAngle, touchAngle, useDirection, ccw);
+ mAcculumalatedTrailAngle += Math.toDegrees(deltaAngle / (double) RADIAN_INT_MULTIPLIER);
+ }
+
if (animateThumbToNewAngle) {
if (useDirection) {
setThumbAngleAnimated(touchAngle, 0, ccw);
@@ -851,15 +863,10 @@ public class ZoomRing extends View {
if (DRAW_TRAIL) {
mTrail.draw(canvas);
}
-
- // If we aren't near the bounds, draw the corresponding arrows
- int callbackAngle = mPreviousCallbackAngle;
- if (callbackAngle < mThumbCwBound - RADIAN_INT_ERROR ||
- callbackAngle > mThumbCwBound + RADIAN_INT_ERROR) {
+ if ((mThumbArrowsToDraw & THUMB_ARROW_PLUS) != 0) {
mThumbPlusArrowDrawable.draw(canvas);
}
- if (callbackAngle < mThumbCcwBound - RADIAN_INT_ERROR ||
- callbackAngle > mThumbCcwBound + RADIAN_INT_ERROR) {
+ if ((mThumbArrowsToDraw & THUMB_ARROW_MINUS) != 0) {
mThumbMinusArrowDrawable.draw(canvas);
}
mThumbDrawable.draw(canvas);
@@ -875,8 +882,21 @@ public class ZoomRing extends View {
public void setThumbArrowsVisible(boolean visible) {
if (visible) {
mThumbArrowsAlpha = 255;
- mThumbPlusArrowDrawable.setAlpha(255);
- mThumbMinusArrowDrawable.setAlpha(255);
+ int callbackAngle = mPreviousCallbackAngle;
+ if (callbackAngle < mThumbCwBound - RADIAN_INT_ERROR ||
+ callbackAngle > mThumbCwBound + RADIAN_INT_ERROR) {
+ mThumbPlusArrowDrawable.setAlpha(255);
+ mThumbArrowsToDraw |= THUMB_ARROW_PLUS;
+ } else {
+ mThumbArrowsToDraw &= ~THUMB_ARROW_PLUS;
+ }
+ if (callbackAngle < mThumbCcwBound - RADIAN_INT_ERROR ||
+ callbackAngle > mThumbCcwBound + RADIAN_INT_ERROR) {
+ mThumbMinusArrowDrawable.setAlpha(255);
+ mThumbArrowsToDraw |= THUMB_ARROW_MINUS;
+ } else {
+ mThumbArrowsToDraw &= ~THUMB_ARROW_MINUS;
+ }
invalidate();
} else if (mThumbArrowsAlpha == 255) {
// Only start fade if we're fully visible (otherwise another fade is happening already)
@@ -886,17 +906,24 @@ public class ZoomRing extends View {
}
private void onThumbArrowsFadeTick() {
- if (mThumbArrowsAlpha <= 0) return;
+ if (mThumbArrowsAlpha <= 0) {
+ mThumbArrowsToDraw = 0;
+ return;
+ }
mThumbArrowsAlpha = (int)
(255 - (255 * (SystemClock.elapsedRealtime() - mThumbArrowsFadeStartTime)
/ THUMB_ARROWS_FADE_DURATION));
if (mThumbArrowsAlpha < 0) mThumbArrowsAlpha = 0;
- mThumbPlusArrowDrawable.setAlpha(mThumbArrowsAlpha);
- mThumbMinusArrowDrawable.setAlpha(mThumbArrowsAlpha);
- invalidateDrawable(mThumbPlusArrowDrawable);
- invalidateDrawable(mThumbMinusArrowDrawable);
-
+ if ((mThumbArrowsToDraw & THUMB_ARROW_PLUS) != 0) {
+ mThumbPlusArrowDrawable.setAlpha(mThumbArrowsAlpha);
+ invalidateDrawable(mThumbPlusArrowDrawable);
+ }
+ if ((mThumbArrowsToDraw & THUMB_ARROW_MINUS) != 0) {
+ mThumbMinusArrowDrawable.setAlpha(mThumbArrowsAlpha);
+ invalidateDrawable(mThumbMinusArrowDrawable);
+ }
+
if (!mHandler.hasMessages(MSG_THUMB_ARROWS_FADE_TICK)) {
mHandler.sendEmptyMessage(MSG_THUMB_ARROWS_FADE_TICK);
}
diff --git a/core/java/android/widget/ZoomRingController.java b/core/java/android/widget/ZoomRingController.java
index 31074b6402698..2e97fdafebade 100644
--- a/core/java/android/widget/ZoomRingController.java
+++ b/core/java/android/widget/ZoomRingController.java
@@ -57,7 +57,7 @@ import android.view.animation.DecelerateInterpolator;
public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
View.OnTouchListener, View.OnKeyListener {
- private static final int ZOOM_RING_RADIUS_INSET = 10;
+ private static final int ZOOM_RING_RADIUS_INSET = 24;
private static final int ZOOM_RING_RECENTERING_DURATION = 500;
@@ -79,7 +79,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
private static final int MAX_PAN_GAP = 20;
private static final int MAX_INITIATE_PAN_GAP = 10;
// TODO view config
- private static final int INITIATE_PAN_DELAY = 400;
+ private static final int INITIATE_PAN_DELAY = 300;
private static final String SETTING_NAME_SHOWN_TOAST = "shown_zoom_ring_toast";
@@ -146,7 +146,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
private int mZoomRingHeight;
/** Invokes panning of owner view if the zoom ring is touching an edge. */
- private Panner mPanner = new Panner();
+ private Panner mPanner;
private long mTouchingEdgeStartTime;
private boolean mPanningEnabledForThisInteraction;
@@ -241,6 +241,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
mContext = context;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ mPanner = new Panner();
mOwnerView = ownerView;
mZoomRing = new ZoomRing(context);
@@ -389,6 +390,8 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
};
}
+ mPanningArrows.setAnimation(null);
+
mHandler.post(mPostedVisibleInitializer);
// Handle configuration changes when visible
@@ -409,12 +412,13 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
} else {
mOwnerView.setOnTouchListener(null);
}
-
+
// No longer care about configuration changes
mContext.unregisterReceiver(mConfigurationChangedReceiver);
mWindowManager.removeView(mContainer);
-
+ mHandler.removeCallbacks(mPostedVisibleInitializer);
+
if (mCallback != null) {
mCallback.onVisibilityChanged(false);
}
@@ -464,6 +468,9 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
public boolean handleDoubleTapEvent(MotionEvent event) {
int action = event.getAction();
+ // TODO: make sure this works well with the
+ // ownerView.setOnTouchListener(this) instead of window receiving
+ // touches
if (action == MotionEvent.ACTION_DOWN) {
mTouchMode = TOUCH_MODE_WAITING_FOR_TAP_DRAG_MOVEMENT;
int x = (int) event.getX();
@@ -493,6 +500,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
mViewConfig.getScaledTouchSlop()) {
mZoomRing.setTapDragMode(true, x, y);
mTouchMode = TOUCH_MODE_FORWARDING_FOR_TAP_DRAG;
+ setTouchTargetView(mZoomRing);
}
return true;
@@ -587,7 +595,6 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
public void onZoomRingMovingStarted() {
mScroller.abortAnimation();
- mPanningEnabledForThisInteraction = false;
mTouchingEdgeStartTime = 0;
if (mCallback != null) {
mCallback.onBeginPan();
@@ -658,6 +665,8 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
if (!horizontalPanning) {
// Neither are panning, reset any timer to start pan mode
mTouchingEdgeStartTime = 0;
+ mPanningEnabledForThisInteraction = false;
+ mPanner.stop();
}
}
}
@@ -752,6 +761,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
// The ring was dismissed but we need to throw away all events until the up
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
mOwnerView.setOnTouchListener(null);
+ setTouchTargetView(null);
mReleaseTouchListenerOnUp = false;
}
@@ -763,16 +773,13 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
switch (action) {
case MotionEvent.ACTION_DOWN:
- targetView = mTouchTargetView =
- getViewForTouch((int) event.getRawX(), (int) event.getRawY());
- if (targetView != null) {
- targetView.getLocationInWindow(mTouchTargetLocationInWindow);
- }
+ targetView = getViewForTouch((int) event.getRawX(), (int) event.getRawY());
+ setTouchTargetView(targetView);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
- mTouchTargetView = null;
+ setTouchTargetView(null);
break;
}
@@ -799,6 +806,13 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
}
}
+ private void setTouchTargetView(View view) {
+ mTouchTargetView = view;
+ if (view != null) {
+ view.getLocationInWindow(mTouchTargetLocationInWindow);
+ }
+ }
+
/**
* Returns the View that should receive a touch at the given coordinates.
*
@@ -950,6 +964,22 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
}
}
+ public void setPannerStartVelocity(float startVelocity) {
+ mPanner.mStartVelocity = startVelocity;
+ }
+
+ public void setPannerAcceleration(float acceleration) {
+ mPanner.mAcceleration = acceleration;
+ }
+
+ public void setPannerMaxVelocity(float maxVelocity) {
+ mPanner.mMaxVelocity = maxVelocity;
+ }
+
+ public void setPannerStartAcceleratingDuration(int duration) {
+ mPanner.mStartAcceleratingDuration = duration;
+ }
+
private class Panner implements Runnable {
private static final int RUN_DELAY = 15;
private static final float STOP_SLOWDOWN = 0.8f;
@@ -967,6 +997,13 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
/** The time of the last callback to pan the map/browser/etc. */
private long mPreviousCallbackTime;
+ // TODO Adjust to be DPI safe
+ private float mStartVelocity = 135;
+ private float mAcceleration = 160;
+ private float mMaxVelocity = 1000;
+ private int mStartAcceleratingDuration = 700;
+ private float mVelocity;
+
/** -100 (full left) to 0 (none) to 100 (full right) */
public void setHorizontalStrength(int horizontalStrength) {
if (mHorizontalStrength == 0 && mVerticalStrength == 0 && horizontalStrength != 0) {
@@ -1013,11 +1050,12 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
boolean firstRun = mPreviousCallbackTime == 0;
long curTime = SystemClock.elapsedRealtime();
- int panAmount = getPanAmount(mStartTime, mPreviousCallbackTime, curTime);
+ int panAmount = getPanAmount(mPreviousCallbackTime, curTime);
mPreviousCallbackTime = curTime;
if (firstRun) {
mStartTime = curTime;
+ mVelocity = mStartVelocity;
} else {
int panX = panAmount * mHorizontalStrength / 100;
int panY = panAmount * mVerticalStrength / 100;
@@ -1030,12 +1068,22 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
mUiHandler.postDelayed(this, RUN_DELAY);
}
- // TODO make setter for this value so zoom clients can have different pan rates, if they want
- private static final int PAN_VELOCITY_PX_S = 30;
- private int getPanAmount(long startTime, long previousTime, long currentTime) {
- return (int) ((currentTime - previousTime) * PAN_VELOCITY_PX_S / 100);
+ private int getPanAmount(long previousTime, long currentTime) {
+ if (mVelocity > mMaxVelocity) {
+ mVelocity = mMaxVelocity;
+ } else if (mVelocity < mMaxVelocity) {
+ // See if it's time to add in some acceleration
+ if (currentTime - mStartTime > mStartAcceleratingDuration) {
+ mVelocity += (currentTime - previousTime) * mAcceleration / 1000;
+ }
+ }
+
+ return (int) ((currentTime - previousTime) * mVelocity) / 1000;
}
+
}
+
+
public interface OnZoomListener {
void onBeginDrag();
diff --git a/core/java/com/android/internal/widget/TextProgressBar.java b/core/java/com/android/internal/widget/TextProgressBar.java
index d068865634723..5bf4601bdff1a 100644
--- a/core/java/com/android/internal/widget/TextProgressBar.java
+++ b/core/java/com/android/internal/widget/TextProgressBar.java
@@ -104,6 +104,7 @@ public class TextProgressBar extends RelativeLayout implements OnChronometerTick
* @param durationBase Use the {@link SystemClock#elapsedRealtime} time
* base.
*/
+ @android.view.RemotableViewMethod
public void setDurationBase(long durationBase) {
mDurationBase = durationBase;
diff --git a/core/java/com/google/android/util/GoogleWebContentHelper.java b/core/java/com/google/android/util/GoogleWebContentHelper.java
index 7500ec3b0db9e..291142008934f 100644
--- a/core/java/com/google/android/util/GoogleWebContentHelper.java
+++ b/core/java/com/google/android/util/GoogleWebContentHelper.java
@@ -206,7 +206,7 @@ public class GoogleWebContentHelper {
WebSettings settings = mWebView.getSettings();
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
- mProgressBar = mLayout.findViewById(com.android.internal.R.id.progress);
+ mProgressBar = mLayout.findViewById(com.android.internal.R.id.progressContainer);
TextView message = (TextView) mProgressBar.findViewById(com.android.internal.R.id.message);
message.setText(com.android.internal.R.string.googlewebcontenthelper_loading);
diff --git a/core/res/res/color/tertiary_text_dark.xml b/core/res/res/color/tertiary_text_dark.xml
index 7e61fc89d8a51..7ce3580f36c9f 100644
--- a/core/res/res/color/tertiary_text_dark.xml
+++ b/core/res/res/color/tertiary_text_dark.xml
@@ -18,7 +18,7 @@

-
+
diff --git a/core/res/res/drawable/sym_action_add.png b/core/res/res/drawable/sym_action_add.png
new file mode 100644
index 0000000000000000000000000000000000000000..af637b3be9d552e5d594057a115b773bf4b4f4c9
GIT binary patch
literal 930
zcmV;T16}-yP)vfqpqY
zK0em(?(Vh$lnjT%+R)ID{NCww#Qpuf4MR>Mk;p+Rm9oAB`1JHtYcv}B(P%V1GczM5
zCnv?o$cP980&<`7?RHz-+}wz2wJKVzRwfpU{a#;Rw?7R`P>>OnC!f3bDMMN6psv1wA-GLGnYrCc$s;&)|K&5kb^k|M>Y%Q^>loZ5nYoJp
zP$(oh=1LB^sxdY;CPBFW`1mOIxpGhkB9g@8=7+$ALP3KPjoi_4a^~>5rwo8Wd5@8K
zOgG`Mx5Mw0r4H(%&ehdbyC*P&bw|1DF+!Q2pP%1-D>{ipf=0N86pO`Q&|#=dcXa9A
zf8OMnUU4d}*c?iwQs1qR|58TDD}5h^8rE7AP#$xlo{giUqupk+DS1OS=QlPsqzBn-
z)74F!dD&;#5o9LsKK|v7RfMsdpRS4=wx(V-}D81b#CpKz2O`lTrGszTwY$b
zKXvD#Ai`xLqcd!cqoboPcT6(XBKeJbPW#MIrWdHMtIzfIH9Hy`eiAa83cb@R3337>
z4i*;|zvk-m)<9b%|LVB278Vx%-(~OTLjMEocl;G#0Md~WU_S;M1&
literal 0
HcmV?d00001
diff --git a/core/res/res/drawable/zoom_ring_track_absolute.png b/core/res/res/drawable/zoom_ring_track_absolute.png
index 6b38c53431f433f067898424f364c75834280e11..0195b9eb70ea7b5a2c3ae4c6969f1d4b3419d892 100644
GIT binary patch
literal 19660
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
diff --git a/core/res/res/layout/google_web_content_helper_layout.xml b/core/res/res/layout/google_web_content_helper_layout.xml
index 74096212781b4..40f84bf8f3da7 100644
--- a/core/res/res/layout/google_web_content_helper_layout.xml
+++ b/core/res/res/layout/google_web_content_helper_layout.xml
@@ -20,7 +20,7 @@
+
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index 53c118872814b..efa6d2bdd3c33 100644
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -113,6 +113,7 @@ static const KeycodeLabel KEYCODES[] = {
{ "PREVIOUSSONG", 88 },
{ "REWIND", 89 },
{ "FORWARD", 90 },
+ { "MUTE", 91 },
// NOTE: If you add a new keycode here you must also add it to:
// (enum KeyCode, in this file)
@@ -216,7 +217,8 @@ typedef enum KeyCode {
kKeyCodeNextSong = 87,
kKeyCodePreviousSong = 88,
kKeyCodeRewind = 89,
- kKeyCodeForward = 90
+ kKeyCodeForward = 90,
+ kKeyCodeMute = 91
} KeyCode;
static const KeycodeLabel FLAGS[] = {
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 3d39181922f1f..e833c85a7890c 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -400,7 +400,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
uint32_t u = cblk->user;
uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
- if (u + framesReady > bufferEnd) {
+ if (u + framesReq > bufferEnd) {
framesReq = bufferEnd - u;
}
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 7fafc562894ec..5416629b8e10a 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -175,27 +175,28 @@ bool ToneGenerator::startTone(int toneType) {
if (mState == TONE_INIT) {
if (prepareWave()) {
LOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000));
-
+ lResult = true;
mState = TONE_STARTING;
mLock.unlock();
mpAudioTrack->start();
mLock.lock();
if (mState == TONE_STARTING) {
+ LOGV("Wait for start callback");
if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR) {
LOGE("--- Immediate start timed out");
mState = TONE_IDLE;
+ lResult = false;
}
}
-
- if (mState == TONE_PLAYING)
- lResult = true;
+ } else {
+ mState == TONE_IDLE;
}
} else {
LOGV("Delayed start\n");
mState = TONE_RESTARTING;
if (mWaitCbkCond.waitRelative(mLock, seconds(1)) == NO_ERROR) {
- if (mState != TONE_INIT) {
+ if (mState != TONE_IDLE) {
lResult = true;
}
LOGV("cond received");
@@ -206,7 +207,8 @@ bool ToneGenerator::startTone(int toneType) {
}
mLock.unlock();
- LOGV("Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
+ LOGV_IF(lResult, "Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
+ LOGW_IF(!lResult, "Tone start failed!!!, time %d\n", (unsigned int)(systemTime()/1000000));
return lResult;
}
@@ -457,8 +459,11 @@ audioCallback_EndLoop:
if (lpToneGen->prepareWave()) {
lpToneGen->mState = TONE_STARTING;
} else {
- lpToneGen->mState = TONE_INIT;
+ LOGW("Cbk restarting prepareWave() failed\n");
+ lpToneGen->mState = TONE_IDLE;
lpToneGen->mpAudioTrack->stop();
+ // Force loop exit
+ lNumSmp = 0;
}
lSignal = true;
break;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
index ae6a834fa66f2..b6a0848aafa92 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
@@ -19,6 +19,8 @@ package com.android.mediaframeworktest.functional;
import com.android.mediaframeworktest.MediaFrameworkTest;
import com.android.mediaframeworktest.MediaNames;
+import android.media.AudioFormat;
+import android.media.AudioManager;
import android.media.AudioTrack;
import android.content.Context;
import android.test.ActivityInstrumentationTestCase2;
@@ -47,12 +49,127 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2= screenWidth
diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
new file mode 100644
index 0000000000000..66fa943d2079c
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.content.Intent;
+import android.provider.Telephony.Sms.Intents;
+import android.util.Config;
+import android.util.Log;
+import com.android.internal.telephony.gsm.GSMPhone;
+import com.android.internal.telephony.gsm.SimUtils;
+
+
+/**
+ * WAP push handler class.
+ *
+ * @hide
+ */
+public class WapPushOverSms {
+ private static final String LOG_TAG = "WAP PUSH";
+
+ private final GSMPhone mPhone;
+ private WspTypeDecoder pduDecoder;
+
+
+ public WapPushOverSms(GSMPhone phone) {
+ mPhone = phone;
+ }
+
+ /**
+ * Dispatches inbound messages that are in the WAP PDU format. See
+ * wap-230-wsp-20010705-a section 8 for details on the WAP PDU format.
+ *
+ * @param pdu The WAP PDU, made up of one or more SMS PDUs
+ */
+ public void dispatchWapPdu(byte[] pdu) {
+
+ if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + SimUtils.bytesToHexString(pdu));
+
+ int index = 0;
+ int transactionId = pdu[index++] & 0xFF;
+ int pduType = pdu[index++] & 0xFF;
+ int headerLength = 0;
+
+ if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH) &&
+ (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
+ if (Config.LOGD) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
+ return;
+ }
+
+ pduDecoder = new WspTypeDecoder(pdu);
+
+ /**
+ * Parse HeaderLen(unsigned integer).
+ * From wap-230-wsp-20010705-a section 8.1.2
+ * The maximum size of a uintvar is 32 bits.
+ * So it will be encoded in no more than 5 octets.
+ */
+ if (pduDecoder.decodeUintvarInteger(index) == false) {
+ if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Length error.");
+ return;
+ }
+ headerLength = (int)pduDecoder.getValue32();
+ index += pduDecoder.getDecodedDataLength();
+
+ int headerStartIndex = index;
+
+ /**
+ * Parse Content-Type.
+ * From wap-230-wsp-20010705-a section 8.4.2.24
+ *
+ * Content-type-value = Constrained-media | Content-general-form
+ * Content-general-form = Value-length Media-type
+ * Media-type = (Well-known-media | Extension-Media) *(Parameter)
+ * Value-length = Short-length | (Length-quote Length)
+ * Short-length = (octet <= WAP_PDU_SHORT_LENGTH_MAX)
+ * Length-quote = (WAP_PDU_LENGTH_QUOTE)
+ * Length = Uintvar-integer
+ */
+ if (pduDecoder.decodeContentType(index) == false) {
+ if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
+ return;
+ }
+ int binaryContentType;
+ String mimeType = pduDecoder.getValueString();
+ if (mimeType == null) {
+ binaryContentType = (int)pduDecoder.getValue32();
+ switch (binaryContentType) {
+ case WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_XML:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_WBXML:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_WBXML;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_PUSH_SI:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SI;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_PUSH_SL:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SL;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_MMS:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS;
+ break;
+ default:
+ if (Config.LOGD) {
+ Log.w(LOG_TAG,
+ "Received PDU. Unsupported Content-Type = " + binaryContentType);
+ }
+ return;
+ }
+ } else {
+ if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_XML;
+ } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_WBXML)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_WBXML;
+ } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SI)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_SI;
+ } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SL)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_SL;
+ } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO;
+ } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_MMS;
+ } else {
+ if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Unknown Content-Type = " + mimeType);
+ return;
+ }
+ }
+ index += pduDecoder.getDecodedDataLength();
+
+ int dataIndex = headerStartIndex + headerLength;
+ boolean dispatchedByApplication = false;
+ switch (binaryContentType) {
+ case WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO:
+ dispatchWapPdu_PushCO(pdu, transactionId, pduType);
+ dispatchedByApplication = true;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_MMS:
+ dispatchWapPdu_MMS(pdu, transactionId, pduType, dataIndex);
+ dispatchedByApplication = true;
+ break;
+ default:
+ break;
+ }
+ if (dispatchedByApplication == false) {
+ dispatchWapPdu_default(pdu, transactionId, pduType, mimeType, dataIndex);
+ }
+ }
+
+
+
+ private void dispatchWapPdu_default(
+ byte[] pdu, int transactionId, int pduType, String mimeType, int dataIndex) {
+ byte[] data;
+
+ data = new byte[pdu.length - dataIndex];
+ System.arraycopy(pdu, dataIndex, data, 0, data.length);
+
+ Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
+ intent.setType(mimeType);
+ intent.putExtra("transactionId", transactionId);
+ intent.putExtra("pduType", pduType);
+ intent.putExtra("data", data);
+
+ mPhone.getContext().sendBroadcast(
+ intent, "android.permission.RECEIVE_WAP_PUSH");
+ }
+
+ private void dispatchWapPdu_PushCO(byte[] pdu, int transactionId, int pduType) {
+ Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
+ intent.setType(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO);
+ intent.putExtra("transactionId", transactionId);
+ intent.putExtra("pduType", pduType);
+ intent.putExtra("data", pdu);
+
+ mPhone.getContext().sendBroadcast(
+ intent, "android.permission.RECEIVE_WAP_PUSH");
+ }
+
+ private void dispatchWapPdu_MMS(byte[] pdu, int transactionId, int pduType, int dataIndex) {
+ byte[] data;
+
+ data = new byte[pdu.length - dataIndex];
+ System.arraycopy(pdu, dataIndex, data, 0, data.length);
+
+ Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
+ intent.setType(WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS);
+ intent.putExtra("transactionId", transactionId);
+ intent.putExtra("pduType", pduType);
+ intent.putExtra("data", data);
+
+ mPhone.getContext().sendBroadcast(
+ intent, "android.permission.RECEIVE_MMS");
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
new file mode 100644
index 0000000000000..2984fa8a576cd
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+
+/**
+ * Implement the WSP data type decoder.
+ *
+ * @hide
+ */
+public class WspTypeDecoder {
+
+ private static final int WAP_PDU_SHORT_LENGTH_MAX = 30;
+ private static final int WAP_PDU_LENGTH_QUOTE = 31;
+
+ public static final int PDU_TYPE_PUSH = 0x06;
+ public static final int PDU_TYPE_CONFIRMED_PUSH = 0x07;
+
+ public static final int CONTENT_TYPE_B_DRM_RIGHTS_XML = 0x4a;
+ public static final int CONTENT_TYPE_B_DRM_RIGHTS_WBXML = 0x4b;
+ public static final int CONTENT_TYPE_B_PUSH_SI = 0x2e;
+ public static final int CONTENT_TYPE_B_PUSH_SL = 0x30;
+ public static final int CONTENT_TYPE_B_PUSH_CO = 0x32;
+ public static final int CONTENT_TYPE_B_MMS = 0x3e;
+
+ public static final String CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML =
+ "application/vnd.oma.drm.rights+xml";
+ public static final String CONTENT_MIME_TYPE_B_DRM_RIGHTS_WBXML =
+ "application/vnd.oma.drm.rights+wbxml";
+ public static final String CONTENT_MIME_TYPE_B_PUSH_SI = "application/vnd.wap.sic";
+ public static final String CONTENT_MIME_TYPE_B_PUSH_SL = "application/vnd.wap.slc";
+ public static final String CONTENT_MIME_TYPE_B_PUSH_CO = "application/vnd.wap.coc";
+ public static final String CONTENT_MIME_TYPE_B_MMS = "application/vnd.wap.mms-message";
+
+ public static final int PARAMETER_ID_X_WAP_APPLICATION_ID = 0x2f;
+
+
+ byte[] wspData;
+ int dataLength;
+ long unsigned32bit;
+ String stringValue;
+
+ public WspTypeDecoder(byte[] pdu) {
+ wspData = pdu;
+ }
+
+ /**
+ * Decode the "Text-string" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Text-string" in this pdu
+ *
+ * @return false when error(not a Text-string) occur
+ * return value can be retrieved by getValueString() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeTextString(int startIndex) {
+ int index = startIndex;
+ while (wspData[index] != 0) {
+ index++;
+ }
+ dataLength = index - startIndex + 1;
+ if (wspData[startIndex] == 127) {
+ stringValue = new String(wspData, startIndex+1, dataLength - 2);
+ } else {
+ stringValue = new String(wspData, startIndex, dataLength - 1);
+ }
+ return true;
+ }
+
+ /**
+ * Decode the "Short-integer" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Short-integer" in this pdu
+ *
+ * @return false when error(not a Short-integer) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeShortInteger(int startIndex) {
+ if ((wspData[startIndex] & 0x80) == 0) {
+ return false;
+ }
+ unsigned32bit = wspData[startIndex] & 0x7f;
+ dataLength = 1;
+ return true;
+ }
+
+ /**
+ * Decode the "Long-integer" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Long-integer" in this pdu
+ *
+ * @return false when error(not a Long-integer) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeLongInteger(int startIndex) {
+ int lengthMultiOctet = wspData[startIndex] & 0xff;
+
+ if (lengthMultiOctet > WAP_PDU_SHORT_LENGTH_MAX) {
+ return false;
+ }
+ unsigned32bit = 0;
+ for (int i=1; i<=lengthMultiOctet; i++) {
+ unsigned32bit = (unsigned32bit << 8) | (wspData[startIndex+i] & 0xff);
+ }
+ dataLength = 1+lengthMultiOctet;
+ return true;
+ }
+
+ /**
+ * Decode the "Integer-Value" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Integer-Value" in this pdu
+ *
+ * @return false when error(not a Integer-Value) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeIntegerValue(int startIndex) {
+ if (decodeShortInteger(startIndex) == true) {
+ return true;
+ }
+ return decodeLongInteger(startIndex);
+ }
+
+ /**
+ * Decode the "Uintvar-integer" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Uintvar-integer" in this pdu
+ *
+ * @return false when error(not a Uintvar-integer) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeUintvarInteger(int startIndex) {
+ int index = startIndex;
+
+ unsigned32bit = 0;
+ while ((wspData[index] & 0x80) != 0) {
+ if ((index - startIndex) >= 4) {
+ return false;
+ }
+ unsigned32bit = (unsigned32bit << 7) | (wspData[index] & 0x7f);
+ index++;
+ }
+ unsigned32bit = (unsigned32bit << 7) | (wspData[index] & 0x7f);
+ dataLength = index - startIndex + 1;
+ return true;
+ }
+
+ /**
+ * Decode the "Value-length" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Value-length" in this pdu
+ *
+ * @return false when error(not a Value-length) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeValueLength(int startIndex) {
+ if ((wspData[startIndex] & 0xff) > WAP_PDU_LENGTH_QUOTE) {
+ return false;
+ }
+ if (wspData[startIndex] < WAP_PDU_LENGTH_QUOTE) {
+ unsigned32bit = wspData[startIndex];
+ dataLength = 1;
+ } else {
+ decodeUintvarInteger(startIndex+1);
+ dataLength ++;
+ }
+ return true;
+ }
+
+ /**
+ * Decode the "Extension-media" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Extension-media" in this pdu
+ *
+ * @return false when error(not a Extension-media) occur
+ * return value can be retrieved by getValueString() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeExtensionMedia(int startIndex) {
+ int index = startIndex;
+ while (wspData[index] != 0) {
+ index++;
+ }
+ dataLength = index - startIndex + 1;
+ stringValue = new String(wspData, startIndex, dataLength - 1);
+ return true;
+ }
+
+ /**
+ * Decode the "Constrained-encoding" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Constrained-encoding" in this pdu
+ *
+ * @return false when error(not a Constrained-encoding) occur
+ * return value can be retrieved first by getValueString() and second by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeConstrainedEncoding(int startIndex) {
+ if (decodeShortInteger(startIndex) == true) {
+ stringValue = null;
+ return true;
+ }
+ return decodeExtensionMedia(startIndex);
+ }
+
+ /**
+ * Decode the "Content-type" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Content-type" in this pdu
+ *
+ * @return false when error(not a Content-type) occur
+ * return value can be retrieved first by getValueString() and second by getValue32()
+ * method length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeContentType(int startIndex) {
+ int mediaPrefixLength;
+ long mediaFieldLength;
+
+ if (decodeValueLength(startIndex) == false) {
+ return decodeConstrainedEncoding(startIndex);
+ }
+ mediaPrefixLength = getDecodedDataLength();
+ mediaFieldLength = getValue32();
+ if (decodeIntegerValue(startIndex + mediaPrefixLength) == true) {
+ dataLength += mediaPrefixLength;
+ stringValue = null;
+ return true;
+ }
+ if (decodeExtensionMedia(startIndex + mediaPrefixLength) == true) {
+ dataLength += mediaPrefixLength;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Decode the "Content length" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Content length" in this pdu
+ *
+ * @return false when error(not a Content length) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeContentLength(int startIndex) {
+ return decodeIntegerValue(startIndex);
+ }
+
+ /**
+ * Decode the "Content location" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Content location" in this pdu
+ *
+ * @return false when error(not a Content location) occur
+ * return value can be retrieved by getValueString() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeContentLocation(int startIndex) {
+ return decodeTextString(startIndex);
+ }
+
+ /**
+ * Decode the "X-Wap-Application-Id" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "X-Wap-Application-Id" in this pdu
+ *
+ * @return false when error(not a X-Wap-Application-Id) occur
+ * return value can be retrieved first by getValueString() and second by getValue32()
+ * method length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeXWapApplicationId(int startIndex) {
+ if (decodeIntegerValue(startIndex) == true) {
+ stringValue = null;
+ return true;
+ }
+ return decodeTextString(startIndex);
+ }
+
+ /**
+ * Decode the "X-Wap-Content-URI" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "X-Wap-Content-URI" in this pdu
+ *
+ * @return false when error(not a X-Wap-Content-URI) occur
+ * return value can be retrieved by getValueString() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeXWapContentURI(int startIndex) {
+ return decodeTextString(startIndex);
+ }
+
+ /**
+ * Decode the "X-Wap-Initiator-URI" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "X-Wap-Initiator-URI" in this pdu
+ *
+ * @return false when error(not a X-Wap-Initiator-URI) occur
+ * return value can be retrieved by getValueString() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeXWapInitiatorURI(int startIndex) {
+ return decodeTextString(startIndex);
+ }
+
+ /**
+ * The data length of latest operation.
+ */
+ public int getDecodedDataLength() {
+ return dataLength;
+ }
+
+ /**
+ * The 32-bits result of latest operation.
+ */
+ public long getValue32() {
+ return unsigned32bit;
+ }
+
+ /**
+ * The String result of latest operation.
+ */
+ public String getValueString() {
+ return stringValue;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
index 417600408fa30..6eea1d49b685a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
@@ -37,6 +37,7 @@ import android.provider.Settings;
import android.provider.Telephony.Sms.Intents;
import android.telephony.gsm.SmsMessage;
import android.telephony.gsm.SmsManager;
+import com.android.internal.telephony.WapPushOverSms;
import android.telephony.ServiceState;
import android.util.Config;
import com.android.internal.util.HexDump;
@@ -62,37 +63,6 @@ final class SMSDispatcher extends Handler {
/** Default timeout for SMS sent query */
private static final int DEFAULT_SMS_TIMOUEOUT = 6000;
- private static final int WAP_PDU_TYPE_PUSH = 0x06;
-
- private static final int WAP_PDU_TYPE_CONFIRMED_PUSH = 0x07;
-
- private static final byte DRM_RIGHTS_XML = (byte)0xca;
-
- private static final String DRM_RIGHTS_XML_MIME_TYPE = "application/vnd.oma.drm.rights+xml";
-
- private static final byte DRM_RIGHTS_WBXML = (byte)0xcb;
-
- private static final String DRM_RIGHTS_WBXML_MIME_TYPE =
- "application/vnd.oma.drm.rights+wbxml";
-
- private static final byte WAP_SI_MIME_PORT = (byte)0xae;
-
- private static final String WAP_SI_MIME_TYPE = "application/vnd.wap.sic";
-
- private static final byte WAP_SL_MIME_PORT = (byte)0xb0;
-
- private static final String WAP_SL_MIME_TYPE = "application/vnd.wap.slc";
-
- private static final byte WAP_CO_MIME_PORT = (byte)0xb2;
-
- private static final String WAP_CO_MIME_TYPE = "application/vnd.wap.coc";
-
- private static final int WAP_PDU_SHORT_LENGTH_MAX = 30;
-
- private static final int WAP_PDU_LENGTH_QUOTE = 31;
-
- private static final String MMS_MIME_TYPE = "application/vnd.wap.mms-message";
-
private static final String[] RAW_PROJECTION = new String[] {
"pdu",
"sequence",
@@ -124,6 +94,8 @@ final class SMSDispatcher extends Handler {
private final GSMPhone mPhone;
+ private final WapPushOverSms mWapPush;
+
private final Context mContext;
private final ContentResolver mResolver;
@@ -208,6 +180,7 @@ final class SMSDispatcher extends Handler {
SMSDispatcher(GSMPhone phone) {
mPhone = phone;
+ mWapPush = new WapPushOverSms(phone);
mContext = phone.getContext();
mResolver = mContext.getContentResolver();
mCm = phone.mCM;
@@ -538,7 +511,7 @@ final class SMSDispatcher extends Handler {
if (destPort != -1) {
if (destPort == SmsHeader.PORT_WAP_PUSH) {
- dispatchWapPdu(sms.getUserData());
+ mWapPush.dispatchWapPdu(sms.getUserData());
}
// The message was sent to a port, so concoct a URI for it
dispatchPortAddressedPdus(pdus, destPort);
@@ -621,7 +594,7 @@ final class SMSDispatcher extends Handler {
}
// Handle the PUSH
- dispatchWapPdu(output.toByteArray());
+ mWapPush.dispatchWapPdu(output.toByteArray());
break;
}
@@ -663,122 +636,6 @@ final class SMSDispatcher extends Handler {
intent, "android.permission.RECEIVE_SMS");
}
- /**
- * Dispatches inbound messages that are in the WAP PDU format. See
- * wap-230-wsp-20010705-a section 8 for details on the WAP PDU format.
- *
- * @param pdu The WAP PDU, made up of one or more SMS PDUs
- */
- private void dispatchWapPdu(byte[] pdu) {
- int index = 0;
- int transactionId = pdu[index++] & 0xFF;
- int pduType = pdu[index++] & 0xFF;
- int headerLength = 0;
-
- if ((pduType != WAP_PDU_TYPE_PUSH) &&
- (pduType != WAP_PDU_TYPE_CONFIRMED_PUSH)) {
- Log.w(TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
- return;
- }
-
- /**
- * Parse HeaderLen(unsigned integer).
- * From wap-230-wsp-20010705-a section 8.1.2
- * The maximum size of a uintvar is 32 bits.
- * So it will be encoded in no more than 5 octets.
- */
- int temp = 0;
- do {
- temp = pdu[index++];
- headerLength = headerLength << 7;
- headerLength |= temp & 0x7F;
- } while ((temp & 0x80) != 0);
-
- int headerStartIndex = index;
-
- /**
- * Parse Content-Type.
- * From wap-230-wsp-20010705-a section 8.4.2.24
- *
- * Content-type-value = Constrained-media | Content-general-form
- * Content-general-form = Value-length Media-type
- * Media-type = (Well-known-media | Extension-Media) *(Parameter)
- * Value-length = Short-length | (Length-quote Length)
- * Short-length = (octet <= WAP_PDU_SHORT_LENGTH_MAX)
- * Length-quote = (WAP_PDU_LENGTH_QUOTE)
- * Length = Uintvar-integer
- */
- // Parse Value-length.
- if ((pdu[index] & 0xff) <= WAP_PDU_SHORT_LENGTH_MAX) {
- // Short-length.
- index++;
- } else if (pdu[index] == WAP_PDU_LENGTH_QUOTE) {
- // Skip Length-quote.
- index++;
- // Skip Length.
- // Now we assume 8bit is enough to store the content-type length.
- index++;
- }
- String mimeType;
- switch (pdu[headerStartIndex])
- {
- case DRM_RIGHTS_XML:
- mimeType = DRM_RIGHTS_XML_MIME_TYPE;
- break;
- case DRM_RIGHTS_WBXML:
- mimeType = DRM_RIGHTS_WBXML_MIME_TYPE;
- break;
- case WAP_SI_MIME_PORT:
- // application/vnd.wap.sic
- mimeType = WAP_SI_MIME_TYPE;
- break;
- case WAP_SL_MIME_PORT:
- mimeType = WAP_SL_MIME_TYPE;
- break;
- case WAP_CO_MIME_PORT:
- mimeType = WAP_CO_MIME_TYPE;
- break;
- default:
- int start = index;
-
- // Skip text-string.
- // Now we assume the mimetype is Extension-Media.
- while (pdu[index++] != '\0') {
- ;
- }
- mimeType = new String(pdu, start, index-start-1);
- break;
- }
-
- // XXX Skip the remainder of the header for now
- int dataIndex = headerStartIndex + headerLength;
- byte[] data;
- if (pdu[headerStartIndex] == WAP_CO_MIME_PORT)
- {
- // because SMSDispatcher can't parse push headers "Content-Location" and
- // X-Wap-Content-URI, so pass the whole push to CO application.
- data = pdu;
- } else
- {
- data = new byte[pdu.length - dataIndex];
- System.arraycopy(pdu, dataIndex, data, 0, data.length);
- }
-
- // Notify listeners about the WAP PUSH
- Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
- intent.setType(mimeType);
- intent.putExtra("transactionId", transactionId);
- intent.putExtra("pduType", pduType);
- intent.putExtra("data", data);
-
- if (mimeType.equals(MMS_MIME_TYPE)) {
- mPhone.getContext().sendBroadcast(
- intent, "android.permission.RECEIVE_MMS");
- } else {
- mPhone.getContext().sendBroadcast(
- intent, "android.permission.RECEIVE_WAP_PUSH");
- }
- }
/**
* Send a multi-part text based SMS.
@@ -913,7 +770,7 @@ final class SMSDispatcher extends Handler {
sendSms(tracker);
}
}
-
+
/**
* Send a SMS
*
diff --git a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
index f37d1ebf6bf95..995173b0f2cf4 100644
--- a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
@@ -35,6 +35,7 @@ import android.database.ContentObserver;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
+import android.os.PowerManager;
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.SystemClock;
@@ -141,6 +142,9 @@ final class ServiceStateTracker extends Handler
// Already sent the event-log for no gprs register
private boolean mReportedGprsNoReg = false;
+ // Wake lock used while setting time of day.
+ private PowerManager.WakeLock mWakeLock;
+ private static final String WAKELOCK_TAG = "ServiceStateTracker";
// Keep track of SPN display rules, so we only broadcast intent if something changes.
private String curSpn = null;
@@ -230,7 +234,11 @@ final class ServiceStateTracker extends Handler
cellLoc = new GsmCellLocation();
newCellLoc = new GsmCellLocation();
- cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
+ PowerManager powerManager =
+ (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+
+ cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
@@ -1348,42 +1356,49 @@ final class ServiceStateTracker extends Handler
return;
}
- if (getAutoTime()) {
- long millisSinceNitzReceived
- = SystemClock.elapsedRealtime() - nitzReceiveTime;
+ try {
+ mWakeLock.acquire();
- if (millisSinceNitzReceived < 0) {
- // Sanity check: something is wrong
- Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled "
- + "backwards since NITZ time was received, "
- + nitz);
- return;
+ if (getAutoTime()) {
+ long millisSinceNitzReceived
+ = SystemClock.elapsedRealtime() - nitzReceiveTime;
+
+ if (millisSinceNitzReceived < 0) {
+ // Sanity check: something is wrong
+ Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled "
+ + "backwards since NITZ time was received, "
+ + nitz);
+ return;
+ }
+
+ if (millisSinceNitzReceived > Integer.MAX_VALUE) {
+ // If the time is this far off, something is wrong > 24 days!
+ Log.i(LOG_TAG, "NITZ: not setting time, processing has taken "
+ + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
+ + " days");
+ return;
+ }
+
+ // Note: with range checks above, cast to int is safe
+ c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
+
+ Log.i(LOG_TAG, "NITZ: Setting time of day to " + c.getTime()
+ + " NITZ receive delay(ms): " + millisSinceNitzReceived
+ + " gained(ms): "
+ + (c.getTimeInMillis() - System.currentTimeMillis())
+ + " from " + nitz);
+
+ SystemClock.setCurrentTimeMillis(c.getTimeInMillis());
+ Log.i(LOG_TAG, "NITZ: after Setting time of day");
}
-
- if (millisSinceNitzReceived > Integer.MAX_VALUE) {
- // If the time is this far off, something is wrong > 24 days!
- Log.i(LOG_TAG, "NITZ: not setting time, processing has taken "
- + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
- + " days");
- return;
+ SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
+ saveNitzTime(c.getTimeInMillis());
+ if (Config.LOGV) {
+ long end = SystemClock.elapsedRealtime();
+ Log.v(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
}
-
- // Note: with range checks above, cast to int is safe
- c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
-
- Log.i(LOG_TAG, "NITZ: Setting time of day to " + c.getTime()
- + " NITZ receive delay(ms): " + millisSinceNitzReceived
- + " gained(ms): "
- + (c.getTimeInMillis() - System.currentTimeMillis())
- + " from " + nitz);
-
- setAndBroadcastNetworkSetTime(c.getTimeInMillis());
- }
- SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
- saveNitzTime(c.getTimeInMillis());
- if (Config.LOGV) {
- long end = SystemClock.elapsedRealtime();
- Log.v(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
+ } finally {
+ mWakeLock.release();
}
} catch (RuntimeException ex) {
Log.e(LOG_TAG, "NITZ: Parsing NITZ time " + nitz, ex);
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
index 36f7b9be52df5..843d844379ae4 100644
--- a/tests/AndroidTests/AndroidManifest.xml
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -44,8 +44,6 @@
-
-
diff --git a/tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java b/tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java
deleted file mode 100644
index 0a60319761e5c..0000000000000
--- a/tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.unit_tests;
-
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothIntent;
-import android.bluetooth.BluetoothClass;
-import android.bluetooth.IBluetoothDeviceCallback;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.SystemProperties;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import junit.framework.Assert;
-
-import java.util.List;
-import java.util.HashSet;
-
-public class BluetoothTest extends AndroidTestCase {
- private static final String TAG = "BluetoothTest";
-
- @MediumTest
- public void testBluetoothSmokeTest() throws Exception {
-
- BluetoothDevice btDevice =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
-
- // TODO: Use a more reliable check to see if this product should
- // support Bluetooth - see bug 988521
- boolean shouldSupportBluetooth = SystemProperties.get("ro.kernel.qemu").equals("0");
-
- assertFalse(shouldSupportBluetooth && btDevice == null);
- if (!shouldSupportBluetooth) {
- Log.i(TAG, "Skipping test - this device does not have bluetooth.");
- return;
- }
-
- boolean bluetoothWasEnabled = btDevice.isEnabled();
-
- if (bluetoothWasEnabled) {
- Log.i(TAG, "Bluetooth already enabled");
- } else {
- Log.i(TAG, "Enabling Bluetooth...");
- btDevice.enable();
- Log.i(TAG, "Bluetooth enabled");
- }
- Assert.assertTrue(btDevice.isEnabled());
-
- String myAddress = btDevice.getAddress();
- Assert.assertTrue(myAddress != null);
- Log.i(TAG, "My Bluetooth Address is " + myAddress);
- Assert.assertFalse(myAddress.equals("00:00:00:00:00:00"));
-
- if (!bluetoothWasEnabled) {
- Log.i(TAG, "Disabling Bluetooth...");
- btDevice.disable();
- Log.i(TAG, "Bluetooth disabled");
- }
- }
-
- private boolean listenA2dp = false;
- private void listenA2dp() {
- if (!listenA2dp) {
- listenA2dp = true;
- getContext().registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE, -1);
- int oldState = intent.getIntExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, -1);
- Log.e(TAG, "A2DP INTENT: state = " + state + " oldState = " + oldState);
- }
- }, new IntentFilter(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION));
- }
- }
-
- @MediumTest
- public void testA2dpSmokeTest() throws Exception {
- listenA2dp();
-
- BluetoothA2dp a2dp = new BluetoothA2dp(getContext());
-
- List sinks = a2dp.listConnectedSinks();
- Log.e(TAG, "listConnectedSinks()...");
- for (String sink : sinks) {
- Log.e(TAG, sink + " state = " + a2dp.getSinkState(sink));
- }
- }
-
- @MediumTest
- public void testA2dpConnect() throws Exception {
- listenA2dp();
- String address = SystemProperties.get("debug.a2dp.address", "");
- BluetoothA2dp a2dp = new BluetoothA2dp(getContext());
- int result = a2dp.connectSink(address);
- Log.e(TAG, "connectSink(" + address + ") = " + result);
- }
-
- @MediumTest
- public void testA2dpDisconnect() throws Exception {
- listenA2dp();
- String address = SystemProperties.get("debug.a2dp.address", "");
- BluetoothA2dp a2dp = new BluetoothA2dp(getContext());
- int result = a2dp.disconnectSink(address);
- Log.e(TAG, "disconnectSink(" + address + ") = " + result);
- }
-
- @MediumTest
- public void testBluetoothEnabled() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
-
- if (device.isEnabled()) {
- Log.i(TAG, "isEnabled() = yes");
- } else {
- Log.i(TAG, "isEnabled() = no");
- }
- }
-
- @MediumTest
- public void testEnableBluetooth() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- device.enable();
- }
-
- @MediumTest
- public void testEnableBluetoothWithCallback() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- if (!device.enable(mCallback)) {
- Log.e(TAG, "enable() failed");
- }
- }
-
- @MediumTest
- public void testDisableBluetooth() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- device.disable();
- }
-
- @LargeTest
- public void testDiscovery() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- if (device.isEnabled()) {
- getContext().registerReceiver((BroadcastReceiver)new TestDiscoveryReceiver(),
- new IntentFilter(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION));
- Log.i(TAG, "Starting discovery...");
- String result = device.startDiscovery() ? "true" : "false";
- Log.i(TAG, "startDiscovery() = " + result);
- }
- }
-
- @LargeTest
- public void testMultipleDiscovery() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- if (device.isEnabled()) {
- getContext().registerReceiver((BroadcastReceiver)new TestDiscoveryReceiver(),
- new IntentFilter(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION));
- String result;
- Log.i(TAG, "Starting multiple discovery...");
- for (int i = 0; i < 5; i++) {
- result = device.startDiscovery() ? "true" : "false";
- Log.i(TAG, "startDiscovery() = " + result);
- }
- }
- }
- private class TestDiscoveryReceiver extends BroadcastReceiver {
- @Override public void onReceive(Context context, Intent intent) {
- String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
- int deviceClass = intent.getIntExtra(BluetoothIntent.CLASS, -1);
- short rssi = intent.getShortExtra(BluetoothIntent.RSSI, (short)-1);
- Log.i(TAG, "Discovered Device: " + address + " " + deviceClass + " " + rssi);
- }
- }
-
- private IBluetoothDeviceCallback mCallback = new IBluetoothDeviceCallback.Stub() {
- public void onEnableResult(int res) {
- String result = "unknown";
- switch (res) {
- case BluetoothDevice.RESULT_SUCCESS:
- result = "success";
- break;
- case BluetoothDevice.RESULT_FAILURE:
- result = "FAILURE";
- break;
- }
- Log.i(TAG, "onEnableResult(" + result + ")");
- }
- public void onGetRemoteServiceChannelResult(String device, int channel) {}
- };
-
- @SmallTest
- public void testCreateBond() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- if (!device.createBond("01:23:45:67:89:AB")) {
- Log.e(TAG, "createBonding() failed");
- }
- }
-
- @SmallTest
- public void testIsPeriodicDiscovery() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- boolean ret = device.isPeriodicDiscovery();
- if (ret) {
- Log.i(TAG, "isPeriodicDiscovery() = TRUE");
- } else {
- Log.i(TAG, "isPeriodicDiscovery() = FALSE");
- }
- }
-
- @LargeTest
- public void testListBondings() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- String[] addresses = device.listBonds();
- if (addresses == null) {
- Log.i(TAG, "Bluetooth disabled");
- return;
- }
- for (String address : addresses) {
- String name = device.getRemoteName(address);
- Log.i(TAG, "BONDING: " + address + " (" + name + ")");
- }
- }
-
- @LargeTest
- public void testListAclConnections() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- String[] addresses = device.listAclConnections();
- if (addresses == null) {
- Log.i(TAG, "Bluetooth disabled");
- return;
- }
- for (String address : addresses) {
- String name = device.getRemoteName(address);
- Log.i(TAG, "CONNECTION: " + address + " (" + name + ")");
- }
- }
-
- @LargeTest
- public void testListRemoteDevices() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- String[] addresses = device.listRemoteDevices();
- if (addresses == null) {
- Log.i(TAG, "Bluetooth disabled");
- return;
- }
- for (String address : addresses) {
- String name = device.getRemoteName(address);
- Log.i(TAG, "KNOWN DEVICE: " + address + " (" + name + ")");
- }
- }
-
- @MediumTest
- public void testSetupBTIntentRecv() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- if (device.isEnabled()) {
- IntentFilter filter = new IntentFilter(BluetoothIntent.ENABLED_ACTION);
- filter.addAction(BluetoothIntent.ENABLED_ACTION);
- filter.addAction(BluetoothIntent.DISABLED_ACTION);
- filter.addAction(BluetoothIntent.NAME_CHANGED_ACTION);
- filter.addAction(BluetoothIntent.DISCOVERY_STARTED_ACTION);
- filter.addAction(BluetoothIntent.DISCOVERY_COMPLETED_ACTION);
- filter.addAction(BluetoothIntent.PAIRING_REQUEST_ACTION);
- filter.addAction(BluetoothIntent.PAIRING_CANCEL_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_DISCONNECT_REQUESTED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_NAME_FAILED_ACTION);
- filter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
- filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
- getContext().registerReceiver(
- (BroadcastReceiver)new BluetoothIntentReceiver(), filter);
- Log.i(TAG, "Listening for BLUETOOTH INTENTS....");
- } else {
- Log.e(TAG, "BT not enabled");
- }
- }
-
-
- private class BluetoothIntentReceiver extends BroadcastReceiver {
- @Override public void onReceive(Context context, Intent intent) {
- String msg = "";
-
- String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
- if (address != null) {
- msg += " address=" + address;
- }
-
- int deviceClass = intent.getIntExtra(BluetoothIntent.CLASS, BluetoothClass.ERROR);
- if (deviceClass != BluetoothClass.ERROR) {
- msg += " class=" + deviceClass;
- }
-
- int rssi = intent.getIntExtra(BluetoothIntent.RSSI, -1);
- if (rssi != -1) {
- msg += " rssi=" + rssi;
- }
-
- String name = intent.getStringExtra(BluetoothIntent.NAME);
- if (name != null) {
- msg += " name=" + name;
- }
-
- int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, -10);
- if (state != -10) {
- msg += " headset state=" + state;
- }
- Log.i(TAG, "BLUETOOTH INTENT: " + intent.getAction() + msg);
- }
- }
-
-
- private static final int[] ALL_SERVICE_CLASSES = new int[] {
- BluetoothClass.Service.LIMITED_DISCOVERABILITY,
- BluetoothClass.Service.POSITIONING,
- BluetoothClass.Service.NETWORKING,
- BluetoothClass.Service.RENDER,
- BluetoothClass.Service.CAPTURE,
- BluetoothClass.Service.OBJECT_TRANSFER,
- BluetoothClass.Service.AUDIO,
- BluetoothClass.Service.TELEPHONY,
- BluetoothClass.Service.INFORMATION
- };
- private void assertOnlyTheseServiceClassesAreSupported(int deviceClass, HashSet serviceClasses) {
- for (int serviceClassType : ALL_SERVICE_CLASSES) {
- Assert.assertEquals(serviceClasses.contains(new Integer(serviceClassType)),
- BluetoothClass.Service.hasService(deviceClass, serviceClassType));
- }
- }
-
- @SmallTest
- public void testDeviceClass() throws Exception {
- // This test does not require bluetooth hardware
- int deviceClass;
- HashSet serviceClasses;
-
- deviceClass = BluetoothClass.ERROR; // bogus class
- serviceClasses = new HashSet();
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.ERROR, BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(BluetoothClass.ERROR, BluetoothClass.Device.getDevice(deviceClass));
-
- deviceClass = 0x10210C; // mac book pro
- serviceClasses = new HashSet();
- serviceClasses.add(BluetoothClass.Service.OBJECT_TRANSFER);
- serviceClasses.add(BluetoothClass.Service.LIMITED_DISCOVERABILITY);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.COMPUTER,
- BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(0x10C, BluetoothClass.Device.getDevice(deviceClass));
-
- // mac book pro with some unused bits set. Expecting the same results
- deviceClass = 0xFF10210F;
- serviceClasses = new HashSet();
- serviceClasses.add(BluetoothClass.Service.OBJECT_TRANSFER);
- serviceClasses.add(BluetoothClass.Service.LIMITED_DISCOVERABILITY);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.COMPUTER,
- BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(0x10C, BluetoothClass.Device.getDevice(deviceClass));
-
- deviceClass = 0x3E0100; // droid.corp.google.com
- serviceClasses = new HashSet();
- serviceClasses.add(BluetoothClass.Service.AUDIO);
- serviceClasses.add(BluetoothClass.Service.OBJECT_TRANSFER);
- serviceClasses.add(BluetoothClass.Service.CAPTURE);
- serviceClasses.add(BluetoothClass.Service.RENDER);
- serviceClasses.add(BluetoothClass.Service.NETWORKING);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.COMPUTER,
- BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(0x100, BluetoothClass.Device.getDevice(deviceClass));
-
- deviceClass = 0x40020C; // Android
- serviceClasses = new HashSet();
- serviceClasses.add(BluetoothClass.Service.TELEPHONY);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.PHONE, BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(0x20C, BluetoothClass.Device.getDevice(deviceClass));
-
- // Motorola T305 & Jabra BT125 & Jabra BT250V
- // This seems to be a very common headset & handsfree device code
- deviceClass = 0x200404;
- serviceClasses = new HashSet();
- serviceClasses.add(BluetoothClass.Service.AUDIO);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.AUDIO_VIDEO,
- BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET,
- BluetoothClass.Device.getDevice(deviceClass));
-
- // Audi UHV 0128
- deviceClass = 0x200408;
- serviceClasses = new HashSet();
- serviceClasses.add(BluetoothClass.Service.AUDIO);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.AUDIO_VIDEO,
- BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE,
- BluetoothClass.Device.getDevice(deviceClass));
- }
-}
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 5d9e140d6614b..eb7d6f559ecb3 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -5,6 +5,7 @@
//
#include "Main.h"
#include "AaptAssets.h"
+#include "ResourceTable.h"
#include
#include
@@ -190,11 +191,20 @@ bail:
ssize_t processAssets(Bundle* bundle, ZipFile* zip,
const sp& assets)
{
+ ResourceFilter filter;
+ status_t status = filter.parse(bundle->getConfigurations());
+ if (status != NO_ERROR) {
+ return -1;
+ }
+
ssize_t count = 0;
const size_t N = assets->getGroupEntries().size();
for (size_t i=0; igetGroupEntries()[i];
+ if (!filter.match(ge.toParams())) {
+ continue;
+ }
ssize_t res = processAssets(bundle, zip, assets, ge);
if (res < 0) {
return res;
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index 1799560dea7e6..fc750e2595ba1 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -28,7 +28,7 @@ import java.util.regex.Matcher;
* Listens for events from the wpa_supplicant server, and passes them on
* to the {@link WifiStateTracker} for handling. Runs in its own thread.
*
- * {@hide}
+ * @hide
*/
public class WifiMonitor {
@@ -119,14 +119,8 @@ public class WifiMonitor {
private final WifiStateTracker mWifiStateTracker;
- private boolean supplicantConnected;
-
- private boolean oneShot;
-
public WifiMonitor(WifiStateTracker tracker) {
mWifiStateTracker = tracker;
- supplicantConnected = false;
- oneShot = true;
}
public void startMonitoring() {
@@ -144,10 +138,17 @@ public class WifiMonitor {
public void run() {
+ if (connectToSupplicant()) {
+ // Send a message indicating that it is now possible to send commands
+ // to the supplicant
+ mWifiStateTracker.notifySupplicantConnection();
+ } else {
+ mWifiStateTracker.notifySupplicantLost();
+ return;
+ }
+
//noinspection InfiniteLoopStatement
for (;;) {
- ensureSupplicantConnection();
-
String eventStr = WifiNative.waitForEvent();
if (eventStr == null) {
@@ -214,42 +215,32 @@ public class WifiMonitor {
handleSupplicantStateChange(eventData);
} else if (event == DRIVER_STATE) {
handleDriverEvent(eventData);
+ } else if (event == TERMINATING) {
+ mWifiStateTracker.notifySupplicantLost();
+ // If supplicant is gone, exit the thread
+ break;
} else {
handleEvent(event, eventData);
- // If supplicant is gone, exit the thread
- if (event == TERMINATING) {
- break;
- }
}
}
}
- private void ensureSupplicantConnection() {
- while (!supplicantConnected) {
- boolean connected;
+ private boolean connectToSupplicant() {
+ int connectTries = 0;
+
+ while (true) {
synchronized (mWifiStateTracker) {
- connected = WifiNative.connectToSupplicant();
- }
- if (!connected) {
- /*
- * If we fail to connect on the very first attempt, send a message
- * indicating a lost connection to the supplicant, so that the
- * receiver can initialize to the proper state.
- */
- if (oneShot) {
- oneShot = false;
- mWifiStateTracker.notifySupplicantLost();
+ if (WifiNative.connectToSupplicant()) {
+ return true;
}
+ }
+ if (connectTries++ < 3) {
nap(5);
} else {
- supplicantConnected = true;
- oneShot = false;
- // Send a message indicating that it is now possible to send commands
- // to the supplicant
- mWifiStateTracker.notifySupplicantConnection();
-
+ break;
}
}
+ return false;
}
private void handlePasswordKeyMayBeIncorrect() {
@@ -287,11 +278,6 @@ public class WifiMonitor {
mWifiStateTracker.notifyScanResultsAvailable();
break;
- case TERMINATING:
- supplicantConnected = false;
- mWifiStateTracker.notifySupplicantLost();
- break;
-
case UNKNOWN:
break;
}
@@ -370,7 +356,7 @@ public class WifiMonitor {
private static void nap(int secs) {
try {
Thread.sleep(secs * 1000);
- } catch (InterruptedException e) {
+ } catch (InterruptedException ignore) {
}
}
}