OSDN Git Service

auto import from //branches/cupcake/...@132569
authorThe Android Open Source Project <initial-contribution@android.com>
Fri, 20 Feb 2009 15:38:31 +0000 (07:38 -0800)
committerThe Android Open Source Project <initial-contribution@android.com>
Fri, 20 Feb 2009 15:38:31 +0000 (07:38 -0800)
52 files changed:
api/current.xml
core/java/android/app/Activity.java
core/java/android/hardware/SensorManager.java
core/java/android/inputmethodservice/SoftInputWindow.java
core/java/android/preference/Preference.java
core/java/android/preference/PreferenceScreen.java
core/java/android/provider/Checkin.java
core/java/android/provider/Gmail.java
core/java/android/provider/MediaStore.java
core/java/android/server/BluetoothDeviceService.java
core/java/android/server/BluetoothEventLoop.java
core/java/android/view/KeyEvent.java
core/java/android/view/OrientationEventListener.java
core/java/android/view/SurfaceHolder.java
core/java/android/view/ViewRoot.java
core/java/android/view/WindowManagerPolicy.java
core/java/android/view/WindowOrientationListener.java
core/java/android/webkit/WebSettings.java
core/java/android/webkit/WebView.java
core/java/android/webkit/WebViewCore.java
core/java/android/webkit/gears/GearsPluginSettings.java [deleted file]
core/java/android/webkit/gears/HtmlDialogAndroid.java [deleted file]
core/java/android/webkit/gears/IGearsDialogService.java [deleted file]
core/java/android/widget/Adapter.java
core/java/android/widget/TextView.java
core/java/android/widget/ZoomRing.java
core/java/android/widget/ZoomRingController.java
core/java/com/android/internal/widget/TextProgressBar.java
core/java/com/google/android/util/GoogleWebContentHelper.java
core/res/res/color/tertiary_text_dark.xml
core/res/res/drawable/sym_action_add.png [new file with mode: 0644]
core/res/res/drawable/zoom_ring_track_absolute.png
core/res/res/layout/google_web_content_helper_layout.xml
core/res/res/values/attrs.xml
include/ui/KeycodeLabels.h
media/libmedia/AudioRecord.cpp
media/libmedia/ToneGenerator.cpp
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStateUnitTestTemplate.java
services/java/com/android/server/PowerManagerService.java
services/java/com/android/server/WindowManagerService.java
telephony/java/com/android/internal/telephony/WapPushOverSms.java [new file with mode: 0644]
telephony/java/com/android/internal/telephony/WspTypeDecoder.java [new file with mode: 0644]
telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
tests/AndroidTests/AndroidManifest.xml
tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java [deleted file]
tools/aapt/Package.cpp
wifi/java/android/net/wifi/WifiMonitor.java

index aa6471b..9ccb8f7 100644 (file)
  visibility="public"
 >
 </field>
+<field name="KEYCODE_MUTE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="91"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="KEYCODE_N"
  type="int"
  transient="false"
 <parameter name="rate" type="int">
 </parameter>
 </constructor>
+<method name="canDetectOrientation"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="disable"
  return="void"
  abstract="false"
index 8236943..849a37d 100644 (file)
@@ -890,9 +890,9 @@ public class Activity extends ContextThemeWrapper
     }
 
     /**
-     * Called after {@link #onCreate} or {@link #onStop} when the current
-     * activity is now being displayed to the user.  It will
-     * be followed by {@link #onRestart}.
+     * Called after {@link #onCreate} &mdash; or after {@link #onRestart} when  
+     * the activity had been stopped, but is now again being displayed to the 
+        * user.  It will be followed by {@link #onResume}.
      *
      * <p><em>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}.
      *
      * <p>For activities that are using raw {@link Cursor} objects (instead of
      * creating them through
@@ -923,6 +923,7 @@ public class Activity extends ContextThemeWrapper
      * thrown.</em></p>
      * 
      * @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.
      * 
      * <p>Note that this method may never be called, in low memory situations
index 3981f27..e232c2c 100644 (file)
@@ -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();
index da67c6d..c37845f 100644 (file)
@@ -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(
index 3820f28..a255438 100644 (file)
@@ -667,7 +667,6 @@ public class Preference implements Comparable<Preference>, 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<Preference>, 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<Preference>, 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<Preference>, 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<Preference>, 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<Preference>, 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<Preference>, OnDependencyChangeLis
      *            {@link #onSaveInstanceState}.
      * @see #onSaveInstanceState
      * @see #restoreHierarchyState
-     * @see #dispatchRestoreInstanceState
      */
     protected void onRestoreInstanceState(Parcelable state) {
         mBaseMethodCalled = true;
index 9929b96..5353b53 100644 (file)
@@ -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) {
index 688e19a..0cdac53 100644 (file)
@@ -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,
index 253dd4a..5b3c223 100644 (file)
@@ -1477,10 +1477,20 @@ public final class Gmail {
                         LABEL_OUTBOX, LABEL_DRAFT, LABEL_ALL,
                         LABEL_SPAM, LABEL_TRASH);
 
+
+        private static final Set<String> USER_MEANINGFUL_SYSTEM_LABELS_SET =
+                Sets.newHashSet(
+                        SORTED_USER_MEANINGFUL_SYSTEM_LABELS.toArray(
+                                new String[]{}));
+
         public static List<String> getSortedUserMeaningfulSystemLabels() {
             return SORTED_USER_MEANINGFUL_SYSTEM_LABELS;
         }
 
+        public static Set<String> 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
index 2897b4e..b91bc9d 100644 (file)
@@ -158,6 +158,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.
      */
index 86d5a1e..fa53a60 100644 (file)
@@ -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<String, Integer> mState = new HashMap<String, Integer>();
         private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
         private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>();
+        // List of all the vendor_id prefix of Bluetooth addresses for which
+        // auto pairing is not attempted
+        private final ArrayList<String>  mAutoPairingBlacklisted =
+                new ArrayList<String>(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) {
index 187ec2c..8b09583 100644 (file)
@@ -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;
index d5434b6..d6ea91c 100644 (file)
@@ -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:
index cddec11..391ba1e 100755 (executable)
@@ -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.
index 21a72e7..3d0dda3 100644 (file)
@@ -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().
      */
index db8829f..3cfaf1b 100644 (file)
@@ -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;
index 051f823..0f15b17 100644 (file)
@@ -129,14 +129,22 @@ 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
          * window manager lock held.
@@ -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 
index 4aa3f7a..5877932 100755 (executable)
@@ -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.
index 5c470cf..4e2b2ab 100644 (file)
@@ -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();
     }
index 4d9a8fb..c59a5fc 100644 (file)
@@ -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);
index 45113ab..a7261c5 100644 (file)
@@ -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 (file)
index d36d3fb..0000000
+++ /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 (file)
index 6209ab9..0000000
+++ /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 (file)
index 82a3bd9..0000000
+++ /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;
-}
index e952dd5..f2b3e2a 100644 (file)
@@ -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);
     
index bdc54ff..c852be5 100644 (file)
@@ -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);
     }
     
     /**
index 22881b3..a29e1a0 100644 (file)
@@ -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);
         }
index 31074b6..2e97fda 100644 (file)
@@ -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();
index d068865..5bf4601 100644 (file)
@@ -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;
         
index 7500ec3..2911420 100644 (file)
@@ -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);
         
index 7e61fc8..7ce3580 100644 (file)
@@ -18,7 +18,7 @@
     <item android:state_enabled="false" android:color="#808080"/>
 ï»¿    <item android:state_window_focused="false" android:color="#808080"/>
     <item android:state_pressed="true" android:color="#808080"/>
-    <item android:state_selected="true" android:color="#808080"/>
+    <item android:state_selected="true" android:color="@android:color/dim_foreground_light"/>
     <item android:color="#808080"/> <!-- not selected -->
 </selector>
 
diff --git a/core/res/res/drawable/sym_action_add.png b/core/res/res/drawable/sym_action_add.png
new file mode 100644 (file)
index 0000000..af637b3
Binary files /dev/null and b/core/res/res/drawable/sym_action_add.png differ
index 6b38c53..0195b9e 100644 (file)
Binary files a/core/res/res/drawable/zoom_ring_track_absolute.png and b/core/res/res/drawable/zoom_ring_track_absolute.png differ
index 7409621..40f84bf 100644 (file)
@@ -20,7 +20,7 @@
         
     <!-- Include the indeterminate progress dialog's layout. -->
     <include
-            android:id="@+id/progress"
+            android:id="@+id/progressContainer"
             layout="@android:layout/progress_dialog" />
             
     <WebView
index 6e6e074..c1a6440 100644 (file)
         <enum name="KEYCODE_PREVIOUSSONG" value="88" />
         <enum name="KEYCODE_REWIND" value="89" />
         <enum name="KEYCODE_FORWARD" value="90" />
+        <enum name="KEYCODE_MUTE" value="91" />
     </attr>
 
     <!-- ***************************************************************** -->
index 53c1188..efa6d2b 100644 (file)
@@ -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[] = {
index 3d39181..e833c85 100644 (file)
@@ -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;
     }
 
index 7fafc56..5416629 100644 (file)
@@ -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;
index ae6a834..b6a0848 100644 (file)
@@ -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<MediaF
     protected void tearDown() throws Exception {     
         super.tearDown();              
     }
+    
+    //-----------------------------------------------------------------
+    // private class to hold test reslts
+    public class TestResults {
+        public boolean mResult = false;
+        public String  mResultLog = "";
+        public TestResults(boolean b, String s) { mResult = b; mResultLog = s; }
+    }
+    
+    //-----------------------------------------------------------------
+    // generic test methods
+    public TestResults constructorTestMultiSampleRate(
+                        // parameters tested by this method
+                        int _inTest_streamType, int _inTest_mode, int _inTest_config,
+                        // parameter-dependent expected results
+                        int _expected_stateForMode) {
+        
+        int[] testSampleRates = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000};
+        String failedRates = "Failure for rate(s): ";
+        boolean localRes, finalRes = true;
+        
+        for(int i = 0 ; i < testSampleRates.length ; i++) {
+            //Log.v("MediaAudioTrackTest", "[ constructorTestMultiSampleRate ] testing "+ testSampleRates[i]);
+            AudioTrack track = null;
+            try {
+                track = new AudioTrack(
+                        _inTest_streamType, 
+                        testSampleRates[i], 
+                        _inTest_config, 
+                        AudioFormat.ENCODING_PCM_16BIT,
+                        AudioTrack.getMinBufferSize(testSampleRates[i], 
+                                _inTest_config, AudioFormat.ENCODING_PCM_16BIT),//testSampleRates[i]*4 
+                        _inTest_mode);
+            } catch(IllegalArgumentException iae) {
+                Log.e("MediaAudioTrackTest", "[ constructorTestMultiSampleRate ] exception at SR "
+                        + testSampleRates[i]+": \n" + iae);
+            }
+            if(track != null) {
+                localRes = (track.getState() == _expected_stateForMode);
+                track.release();
+            }
+            else {
+                localRes = false;
+            }
+            
+            if (!localRes) {
+                //log the error for the test runner
+                failedRates += Integer.toString(testSampleRates[i]) + "Hz ";
+                //log the error for logcat
+                Log.e("MediaAudioTrackTest", "[ constructorTestMultiSampleRate ] failed to construct "
+                        +"AudioTrack(streamType="+_inTest_streamType 
+                        +", sampleRateInHz=" + testSampleRates[i]
+                        +", channelConfig=" + _inTest_config
+                        +", audioFormat=AudioFormat.ENCODING_PCM_16BIT"  
+                        +", bufferSizeInBytes=" + AudioTrack.getMinBufferSize(testSampleRates[i], 
+                                _inTest_config, AudioFormat.ENCODING_PCM_16BIT)
+                        +", mode="+ _inTest_mode );
+                //mark test as failed
+                finalRes = false;
+            }
+        }
+        return new TestResults(finalRes, failedRates);
+    }
+    
+    //-----------------------------------------------------------------
+    // AUDIOTRACK TESTS:
+    //----------------------------------
+    
+    //-----------------------------------------------------------------
+    //      AudioTrack constructor and AudioTrack.getMinBufferSize(...)
+    //----------------------------------
        
-    //Test case 1: Set the invalid volume
+    //Test case 1: constructor for streaming AudioTrack, mono, 16bit at misc valid sample rates
+    @MediumTest
+    public void testConstructorMono16MusicStream() throws Exception {
+        
+        TestResults res = constructorTestMultiSampleRate(
+                AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM, 
+                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
+                AudioTrack.STATE_INITIALIZED);
+
+        assertTrue("testConstructorMono16MusicStream: " + res.mResultLog, res.mResult);
+    }
+    
+    
+    //Test case 2: constructor for streaming AudioTrack, stereo, 16bit at misc valid sample rates
     @MediumTest
-    public void testGetMinVolume() throws Exception {
-        //To Do: Create the test case for GetMinVolume  
-        assertTrue("testGetMinVolume", true);  
+    public void testConstructorStereo16MusicStream() throws Exception {
+        
+        TestResults res = constructorTestMultiSampleRate(
+                AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM, 
+                    AudioFormat.CHANNEL_CONFIGURATION_STEREO,
+                AudioTrack.STATE_INITIALIZED);
+
+        assertTrue("testConstructorStereo16MusicStream: " + res.mResultLog, res.mResult);
+    }
+    
+    
+    //Test case 3: constructor for static AudioTrack, mono, 16bit at misc valid sample rates
+    @MediumTest
+    public void testConstructorMono16MusicStatic() throws Exception {
+        
+        TestResults res = constructorTestMultiSampleRate(
+                AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC, 
+                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
+                AudioTrack.STATE_NO_STATIC_DATA);
+
+        assertTrue("testConstructorMono16MusicStatic: " + res.mResultLog, res.mResult);
+    }
+    
+    
+    //Test case 4: constructor for static AudioTrack, stereo, 16bit at misc valid sample rates
+    @MediumTest
+    public void testConstructorStereo16MusicStatic() throws Exception {
+        
+        TestResults res = constructorTestMultiSampleRate(
+                AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC, 
+                    AudioFormat.CHANNEL_CONFIGURATION_STEREO,
+                AudioTrack.STATE_NO_STATIC_DATA);
+
+        assertTrue("testConstructorStereo16MusicStatic: " + res.mResultLog, res.mResult);
     }
 
 }
index 0209305..da18e74 100644 (file)
@@ -88,7 +88,7 @@ import android.media.AudioManager;
 
         toneGen = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
 
-        for (type = ToneGenerator.TONE_PROP_BEEP; type <= ToneGenerator.TONE_PROP_PROMPT; type++) {
+        for (type = ToneGenerator.TONE_PROP_BEEP; type <= ToneGenerator.TONE_PROP_BEEP2; type++) {
             if (toneGen.startTone(type)) {
                 Thread.sleep(1000);
                 toneGen.stopTone();
index dfd544a..134144d 100644 (file)
@@ -55,7 +55,7 @@ public class MediaRecorderPrepareStateUnitTest extends AndroidTestCase implement
         try {
             recorder.prepare();
         } catch (IOException exception) {
-            fail("recorder.prepare() failed");
+            throw new RuntimeException();
         }
     }
 
index 50e235b..712a758 100644 (file)
@@ -29,24 +29,22 @@ public class MediaRecorderSetOutputFileStateUnitTest extends AndroidTestCase imp
     private MediaRecorderStateUnitTestTemplate mTestTemplate = new MediaRecorderStateUnitTestTemplate();
     /**
      * 1. It is valid to call setOutputFile() in the following states:
-     *    {DataSourceConfigured}.
+     *    {DataSourceConfigured, Initial, Initialized, Prepared, Recording, Error}.
      * 2. It is invalid to call setOutputFile() in the following states:
-     *    {Initial, Initialized, Prepared, Recording, Error}
+     *    {}
      *    
      * @param stateErrors the MediaRecorderStateErrors to check against.
      */
     public void checkStateErrors(MediaRecorderStateErrors stateErrors) {
         // Valid states.
         assertTrue(!stateErrors.errorInDataSourceConfiguredState);
-
-        // Invalid states.
-        assertTrue(stateErrors.errorInPreparedState);
-        assertTrue(stateErrors.errorInRecordingState);
-        assertTrue(stateErrors.errorInErrorState);
-        assertTrue(stateErrors.errorInInitialState);
-        assertTrue(stateErrors.errorInInitialStateAfterReset);
-        assertTrue(stateErrors.errorInInitialStateAfterStop);
-        assertTrue(stateErrors.errorInInitializedState);
+        assertTrue(!stateErrors.errorInPreparedState);
+        assertTrue(!stateErrors.errorInRecordingState);
+        assertTrue(!stateErrors.errorInErrorState);
+        assertTrue(!stateErrors.errorInInitialState);
+        assertTrue(!stateErrors.errorInInitialStateAfterReset);
+        assertTrue(!stateErrors.errorInInitialStateAfterStop);
+        assertTrue(!stateErrors.errorInInitializedState);
     }
 
     public void invokeMethodUnderTest(MediaRecorder recorder) {
index f350467..9edc9aa 100644 (file)
@@ -90,9 +90,15 @@ class MediaRecorderStateUnitTestTemplate extends AndroidTestCase {
         }
     }
 
+    // FIXME:
+    // In the past, stop() == reset().
+    // However, this is no longer true. The plan is to have a STOPPED state.
+    // and from STOPPED state, start can be called without the need to
+    // do the recording configuration again. 
     private void setMediaRecorderToInitialStateAfterStop() {
         try {
             mMediaRecorder.reset();
+/*
             mMediaRecorder.setAudioSource(AUDIO_SOURCE);
             mMediaRecorder.setOutputFormat(OUTPUT_FORMAT);
             mMediaRecorder.setAudioEncoder(AUDIO_ENCODER);
@@ -100,6 +106,7 @@ class MediaRecorderStateUnitTestTemplate extends AndroidTestCase {
             mMediaRecorder.prepare();
             mMediaRecorder.start();
             mMediaRecorder.stop();
+*/
         } catch(Exception e) {
             fail("setMediaRecorderToInitialStateAfterReset: Exception " + e.getClass().getName() + " was thrown.");
         }
index 16b5819..f41d21f 100644 (file)
@@ -246,8 +246,13 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
 
         public void acquire() {
             if (!mRefCounted || mCount++ == 0) {
-                PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
-                        MY_UID, mTag);
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
+                            MY_UID, mTag);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             }
         }
 
@@ -1285,8 +1290,9 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
                     } finally {
                         Binder.restoreCallingIdentity(identity);
                     }
+                    mPowerState &= ~SCREEN_ON_BIT;
                     if (!mScreenBrightness.animating) {
-                        err = turnScreenOffLocked(becauseOfUser);
+                        err = screenOffFinishedAnimating(becauseOfUser);
                     } else {
                         mOffBecauseOfUser = becauseOfUser;
                         err = 0;
@@ -1297,33 +1303,25 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
         }
     }
     
-    private int turnScreenOffLocked(boolean becauseOfUser) {
-        if ((mPowerState&SCREEN_ON_BIT) != 0) {
-            EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 0, becauseOfUser ? 1 : 0,
-                    mTotalTouchDownTime, mTouchCycles);
-            mLastTouchDown = 0;
-            int err = Power.setScreenState(false);
+    private int screenOffFinishedAnimating(boolean becauseOfUser) {
+        // I don't think we need to check the current state here because all of these
+        // Power.setScreenState and sendNotificationLocked can both handle being 
+        // called multiple times in the same state. -joeo
+        EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 0, becauseOfUser ? 1 : 0,
+                mTotalTouchDownTime, mTouchCycles);
+        mLastTouchDown = 0;
+        int err = Power.setScreenState(false);
+        if (mScreenOnStartTime != 0) {
             mScreenOnTime += SystemClock.elapsedRealtime() - mScreenOnStartTime;
             mScreenOnStartTime = 0;
-            if (err == 0) {
-                // 
-                //      FIXME(joeo)
-                //
-                // The problem that causes the screen not to come on is that this isn't
-                // called until after the animation is done.  It needs to be set right
-                // away, and the anmiation's state needs to be recorded separately.
-                // 
-                // 
-                
-                mPowerState &= ~SCREEN_ON_BIT;
-                int why = becauseOfUser
-                        ? WindowManagerPolicy.OFF_BECAUSE_OF_USER
-                        : WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
-                sendNotificationLocked(false, why);
-            }
-            return err;
         }
-        return 0;
+        if (err == 0) {
+            int why = becauseOfUser
+                    ? WindowManagerPolicy.OFF_BECAUSE_OF_USER
+                    : WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
+            sendNotificationLocked(false, why);
+        }
+        return err;
     }
 
     private boolean batteryIsLow() {
@@ -1538,7 +1536,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
             animating = more;
             if (!more) {
                 if (mask == Power.SCREEN_LIGHT && curIntValue == Power.BRIGHTNESS_OFF) {
-                    turnScreenOffLocked(mOffBecauseOfUser);
+                    screenOffFinishedAnimating(mOffBecauseOfUser);
                 }
             }
             return more;
index fc22bad..10a2d29 100644 (file)
@@ -2088,6 +2088,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
                     }
                 }
                 int or = wtoken.requestedOrientation;
+                // If this application is fullscreen, then just take whatever
+                // orientation it has and ignores whatever is under it.
+                if (wtoken.appFullscreen) {
+                    return or;
+                }
                 // If this application has requested an explicit orientation,
                 // then use it.
                 if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
@@ -5594,6 +5599,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
             return mFrame;
         }
 
+        public Rect getShownFrameLw() {
+            return mShownFrame;
+        }
+
         public Rect getDisplayFrameLw() {
             return mDisplayFrame;
         }
@@ -6221,10 +6230,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
         }
 
         public boolean fillsScreenLw(int screenWidth, int screenHeight,
-                                   boolean shownFrame) {
+                                   boolean shownFrame, boolean onlyOpaque) {
             if (mSurface == null) {
                 return false;
             }
+            if (mAppToken != null && !mAppToken.appFullscreen) {
+                return false;
+            }
+            if (onlyOpaque && mAttrs.format != PixelFormat.OPAQUE) {
+                return false;
+            }
             final Rect frame = shownFrame ? mShownFrame : mFrame;
             if (frame.left <= 0 && frame.top <= 0
                     && frame.right >= 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 (file)
index 0000000..66fa943
--- /dev/null
@@ -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 = <Any octet 0-30>   (octet <= WAP_PDU_SHORT_LENGTH_MAX)
+         * Length-quote = <Octet 31>         (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 (file)
index 0000000..2984fa8
--- /dev/null
@@ -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;
+    }
+}
index 4176004..6eea1d4 100644 (file)
@@ -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 = <Any octet 0-30>   (octet <= WAP_PDU_SHORT_LENGTH_MAX)
-         * Length-quote = <Octet 31>         (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
      *
index f37d1eb..995173b 100644 (file)
@@ -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;
-                }
+                    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);
+                    // 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);
+                    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));
+                    SystemClock.setCurrentTimeMillis(c.getTimeInMillis());
+                    Log.i(LOG_TAG, "NITZ: after Setting time of day");
+                }
+                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);
index 36f7b9b..843d844 100644 (file)
@@ -44,8 +44,6 @@
     <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
     <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
     <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
-    <uses-permission android:name="android.permission.BLUETOOTH" />
-    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.WRITE_GSERVICES" />
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 (file)
index 0a60319..0000000
+++ /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<String> 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", "<none>");
-        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", "<none>");
-        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<Integer> 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<Integer> serviceClasses;
-
-        deviceClass = BluetoothClass.ERROR;  // bogus class
-        serviceClasses = new HashSet<Integer>();
-        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<Integer>();
-        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<Integer>();
-        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<Integer>();
-        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<Integer>();
-        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<Integer>();
-        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<Integer>();
-        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));
-    }
-}
index 5d9e140..eb7d6f5 100644 (file)
@@ -5,6 +5,7 @@
 //
 #include "Main.h"
 #include "AaptAssets.h"
+#include "ResourceTable.h"
 
 #include <utils.h>
 #include <utils/ZipFile.h>
@@ -190,11 +191,20 @@ bail:
 ssize_t processAssets(Bundle* bundle, ZipFile* zip,
                       const sp<AaptAssets>& 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; i<N; i++) {
         const AaptGroupEntry& ge = assets->getGroupEntries()[i];
+        if (!filter.match(ge.toParams())) {
+            continue;
+        }
         ssize_t res = processAssets(bundle, zip, assets, ge);
         if (res < 0) {
             return res;
index 1799560..fc750e2 100644 (file)
@@ -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) {
         }
     }
 }