summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/content/Intent.java8
-rw-r--r--core/java/android/content/pm/PackageParser.java5
-rw-r--r--core/java/android/content/res/AssetManager.java4
-rw-r--r--core/java/android/emoji/EmojiFactory.java273
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java8
-rw-r--r--core/java/android/provider/Checkin.java2
-rw-r--r--core/java/android/server/BluetoothDeviceService.java33
-rw-r--r--core/java/android/server/BluetoothEventLoop.java9
-rw-r--r--core/java/android/text/method/ArrowKeyMovementMethod.java2
-rw-r--r--core/java/android/text/method/MetaKeyKeyListener.java10
-rw-r--r--core/java/android/view/GestureDetector.java3
-rw-r--r--core/java/android/view/HapticFeedbackConstants.java3
-rw-r--r--core/java/android/view/View.java78
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java9
-rw-r--r--core/java/android/view/inputmethod/EditorInfo.java34
-rw-r--r--core/java/android/view/inputmethod/ExtractedText.java7
-rw-r--r--core/java/android/view/inputmethod/InputConnection.java3
-rw-r--r--core/java/android/view/inputmethod/InputConnectionWrapper.java105
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java37
-rw-r--r--core/java/android/webkit/TextDialog.java28
-rw-r--r--core/java/android/webkit/WebView.java301
-rw-r--r--core/java/android/widget/AbsListView.java47
-rw-r--r--core/java/android/widget/FastScroller.java18
-rw-r--r--core/java/android/widget/Filter.java11
-rw-r--r--core/java/android/widget/MediaController.java1
-rw-r--r--core/java/android/widget/TextView.java215
-rw-r--r--core/java/android/widget/VideoView.java19
-rw-r--r--core/java/android/widget/ZoomButtonsController.java179
-rw-r--r--core/java/android/widget/ZoomControls.java2
-rw-r--r--core/java/android/widget/ZoomRing.java1274
-rw-r--r--core/java/android/widget/ZoomRingController.java1383
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl2
-rw-r--r--core/jni/Android.mk8
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rwxr-xr-xcore/jni/android_bluetooth_BluetoothAudioGateway.cpp2
-rw-r--r--core/jni/android_emoji_EmojiFactory.cpp292
-rw-r--r--core/jni/android_net_wifi_Wifi.cpp12
-rw-r--r--core/jni/server/Android.mk40
-rw-r--r--core/jni/server/com_android_server_AlarmManagerService.cpp143
-rw-r--r--core/jni/server/com_android_server_BatteryService.cpp274
-rw-r--r--core/jni/server/com_android_server_HardwareService.cpp54
-rw-r--r--core/jni/server/com_android_server_KeyInputQueue.cpp320
-rw-r--r--core/jni/server/com_android_server_SensorService.cpp125
-rw-r--r--core/jni/server/com_android_server_SystemServer.cpp47
-rw-r--r--core/jni/server/onload.cpp36
-rw-r--r--core/res/Android.mk2
-rw-r--r--core/res/res/anim/zoom_ring_enter.xml29
-rw-r--r--core/res/res/anim/zoom_ring_exit.xml28
-rw-r--r--core/res/res/drawable-land/statusbar_background.pngbin1059 -> 2804 bytes
-rw-r--r--core/res/res/drawable/btn_circle.xml32
-rw-r--r--core/res/res/drawable/btn_circle_disable.pngbin0 -> 938 bytes
-rw-r--r--core/res/res/drawable/btn_circle_disable_focused.pngbin0 -> 1436 bytes
-rw-r--r--core/res/res/drawable/btn_circle_longpress.pngbin0 -> 1590 bytes
-rw-r--r--core/res/res/drawable/btn_circle_normal.pngbin0 -> 1249 bytes
-rw-r--r--core/res/res/drawable/btn_circle_pressed.pngbin0 -> 1613 bytes
-rw-r--r--core/res/res/drawable/btn_circle_selected.pngbin0 -> 1645 bytes
-rw-r--r--core/res/res/drawable/extract_edit_text.xml1
-rw-r--r--core/res/res/drawable/ic_btn_round_more.xml (renamed from core/res/res/drawable/zoom_ring_thumb_plus_arrow_rotatable.xml)12
-rw-r--r--core/res/res/drawable/ic_btn_round_more_disabled.pngbin0 -> 421 bytes
-rw-r--r--core/res/res/drawable/ic_btn_round_more_normal.pngbin0 -> 968 bytes
-rw-r--r--core/res/res/drawable/keyboard_textfield_pressed.9.pngbin1039 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_phone_call.pngbin772 -> 773 bytes
-rw-r--r--core/res/res/drawable/stat_sys_phone_call_bluetooth.pngbin0 -> 815 bytes
-rw-r--r--core/res/res/drawable/statusbar_background.pngbin933 -> 3079 bytes
-rw-r--r--core/res/res/drawable/zoom_ring_arrows.pngbin4187 -> 0 bytes
-rw-r--r--core/res/res/drawable/zoom_ring_overview_tab.9.pngbin1792 -> 0 bytes
-rw-r--r--core/res/res/drawable/zoom_ring_thumb.pngbin2684 -> 0 bytes
-rw-r--r--core/res/res/drawable/zoom_ring_thumb_minus.pngbin201 -> 0 bytes
-rw-r--r--core/res/res/drawable/zoom_ring_thumb_minus_arrow.pngbin1941 -> 0 bytes
-rw-r--r--core/res/res/drawable/zoom_ring_thumb_minus_arrow_rotatable.xml22
-rw-r--r--core/res/res/drawable/zoom_ring_thumb_plus.pngbin317 -> 0 bytes
-rw-r--r--core/res/res/drawable/zoom_ring_thumb_plus_arrow.pngbin2272 -> 0 bytes
-rw-r--r--core/res/res/drawable/zoom_ring_track.pngbin17749 -> 0 bytes
-rw-r--r--core/res/res/drawable/zoom_ring_track_absolute.pngbin18612 -> 0 bytes
-rw-r--r--core/res/res/drawable/zoom_ring_trail.xml37
-rw-r--r--core/res/res/layout/preferences.xml5
-rw-r--r--core/res/res/values/arrays.xml7
-rw-r--r--core/res/res/values/attrs.xml47
-rw-r--r--core/res/res/values/styles.xml20
-rw-r--r--core/res/res/values/themes.xml1
80 files changed, 1331 insertions, 4380 deletions
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e1c1f64..824fd9b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1042,6 +1042,14 @@ public class Intent implements Parcelable {
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON";
+
+ /**
+ * Broadcast Action: Sent when the user is present after device wakes up (e.g when the
+ * keyguard is gone).
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USER_PRESENT= "android.intent.action.USER_PRESENT";
+
/**
* Broadcast Action: The current time has changed. Sent every
* minute. You can <em>not</em> receive this through components declared
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4ae8b08..2dcb483 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -260,8 +260,9 @@ public class PackageParser {
boolean assetError = true;
try {
assmgr = new AssetManager();
- if(assmgr.addAssetPath(mArchiveSourcePath) != 0) {
- parser = assmgr.openXmlResourceParser("AndroidManifest.xml");
+ int cookie = assmgr.addAssetPath(mArchiveSourcePath);
+ if(cookie != 0) {
+ parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
assetError = false;
} else {
Log.w(TAG, "Failed adding asset path:"+mArchiveSourcePath);
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index fadcb35..1c91736 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -567,8 +567,8 @@ public final class AssetManager {
/**
* Add an additional set of assets to the asset manager. This can be
- * either a directory or ZIP file. Not for use by applications. A
- * zero return value indicates failure.
+ * either a directory or ZIP file. Not for use by applications. Returns
+ * the cookie of the added asset, or 0 on failure.
* {@hide}
*/
public native final int addAssetPath(String path);
diff --git a/core/java/android/emoji/EmojiFactory.java b/core/java/android/emoji/EmojiFactory.java
new file mode 100644
index 0000000..389bd07
--- /dev/null
+++ b/core/java/android/emoji/EmojiFactory.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.emoji;
+
+import android.graphics.Bitmap;
+
+import java.lang.ref.WeakReference;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * A class for the factories which produce Emoji (pictgram) images.
+ * This is intended to be used by IME, Email app, etc.
+ * There's no plan to make this public for now.
+ * @hide
+ */
+public final class EmojiFactory {
+ // private static final String LOG_TAG = "EmojiFactory";
+
+ private int sCacheSize = 100;
+
+ // HashMap for caching Bitmap object. In order not to make an cache object
+ // blow up, we use LinkedHashMap with size limit.
+ private class CustomLinkedHashMap<K, V> extends LinkedHashMap<K, V> {
+ public CustomLinkedHashMap() {
+ // These magic numbers are gotten from the source code of
+ // LinkedHashMap.java and HashMap.java.
+ super(16, 0.75f, true);
+ }
+
+ /*
+ * If size() becomes more than sCacheSize, least recently used cache
+ * is erased.
+ * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry)
+ */
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+ return size() > sCacheSize;
+ }
+ }
+
+ // A pointer to native EmojiFactory object.
+ private int mNativeEmojiFactory;
+ private String mName;
+ // Cache.
+ private Map<Integer, WeakReference<Bitmap>> mCache;
+
+ /**
+ * @noinspection UnusedDeclaration
+ */
+ /*
+ * Private constructor that must received an already allocated native
+ * EmojiFactory int (pointer).
+ *
+ * This can be called from JNI code.
+ */
+ private EmojiFactory(int nativeEmojiFactory, String name) {
+ mNativeEmojiFactory = nativeEmojiFactory;
+ mName = name;
+ mCache = new CustomLinkedHashMap<Integer, WeakReference<Bitmap>>();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ nativeDestructor(mNativeEmojiFactory);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ public String name() {
+ return mName;
+ }
+
+ /**
+ * Returns Bitmap object corresponding to the AndroidPua.
+ *
+ * Note that each Bitmap is cached by this class, which means that, if you modify a
+ * Bitmap object (using setPos() method), all same emoji Bitmap will be modified.
+ * If it is unacceptable, please copy the object before modifying it.
+ *
+ * @param pua A unicode codepoint.
+ * @return Bitmap object when this factory knows the Bitmap relevant to the codepoint.
+ * Otherwise null is returned.
+ */
+ public synchronized Bitmap getBitmapFromAndroidPua(int pua) {
+ WeakReference<Bitmap> cache = mCache.get(pua);
+ if (cache == null) {
+ Bitmap ret = nativeGetBitmapFromAndroidPua(mNativeEmojiFactory, pua);
+ // There is no need to cache returned null, since in most cases it means there
+ // is no map from the AndroidPua to a specific image. In other words, it usually does
+ // not include the cost of creating Bitmap object.
+ if (ret != null) {
+ mCache.put(pua, new WeakReference<Bitmap>(ret));
+ }
+ return ret;
+ } else {
+ Bitmap tmp = cache.get();
+ if (tmp == null) {
+ Bitmap ret = nativeGetBitmapFromAndroidPua(mNativeEmojiFactory, pua);
+ mCache.put(pua, new WeakReference<Bitmap>(ret));
+ return ret;
+ } else {
+ return tmp;
+ }
+ }
+ }
+
+ /**
+ * Returns Bitmap object corresponding to the vendor specified sjis.
+ *
+ * See comments in getBitmapFromAndroidPua().
+ *
+ * @param sjis sjis code specific to each career(vendor)
+ * @return Bitmap object when this factory knows the Bitmap relevant to the code. Otherwise
+ * null is returned.
+ */
+ public synchronized Bitmap getBitmapFromVendorSpecificSjis(char sjis) {
+ return getBitmapFromAndroidPua(getAndroidPuaFromVendorSpecificSjis(sjis));
+ }
+
+ /**
+ * Returns Bitmap object corresponding to the vendor specific Unicode.
+ *
+ * See comments in getBitmapFromAndroidPua().
+ *
+ * @param vsp vendor specific PUA.
+ * @return Bitmap object when this factory knows the Bitmap relevant to the code. Otherwise
+ * null is returned.
+ */
+ public synchronized Bitmap getBitmapFromVendorSpecificPua(int vsp) {
+ return getBitmapFromAndroidPua(getAndroidPuaFromVendorSpecificPua(vsp));
+ }
+
+ /**
+ * Returns Unicode PUA for Android corresponding to the vendor specific sjis.
+ *
+ * @param sjis vendor specific sjis
+ * @return Unicode PUA for Android, or -1 if there's no map for the sjis.
+ */
+ public int getAndroidPuaFromVendorSpecificSjis(char sjis) {
+ return nativeGetAndroidPuaFromVendorSpecificSjis(mNativeEmojiFactory, sjis);
+ }
+
+ /**
+ * Returns vendor specific sjis corresponding to the Unicode AndroidPua.
+ *
+ * @param pua Unicode PUA for Android,
+ * @return vendor specific sjis, or -1 if there's no map for the AndroidPua.
+ */
+ public int getVendorSpecificSjisFromAndroidPua(int pua) {
+ return nativeGetVendorSpecificSjisFromAndroidPua(mNativeEmojiFactory, pua);
+ }
+
+ /**
+ * Returns Unicode PUA for Android corresponding to the vendor specific Unicode.
+ *
+ * @param vsp vendor specific PUA.
+ * @return Unicode PUA for Android, or -1 if there's no map for the
+ * Unicode.
+ */
+ public int getAndroidPuaFromVendorSpecificPua(int vsp) {
+ return nativeGetAndroidPuaFromVendorSpecificPua(mNativeEmojiFactory, vsp);
+ }
+
+ public String getAndroidPuaFromVendorSpecificPua(String vspString) {
+ if (vspString == null) {
+ return null;
+ }
+ int minVsp = nativeGetMinimumVendorSpecificPua(mNativeEmojiFactory);
+ int maxVsp = nativeGetMaximumVendorSpecificPua(mNativeEmojiFactory);
+ int len = vspString.length();
+ int[] codePoints = new int[vspString.codePointCount(0, len)];
+
+ int new_len = 0;
+ for (int i = 0; i < len; i = vspString.offsetByCodePoints(i, 1), new_len++) {
+ int codePoint = vspString.codePointAt(i);
+ if (minVsp <= codePoint && codePoint <= maxVsp) {
+ int newCodePoint = getAndroidPuaFromVendorSpecificPua(codePoint);
+ if (newCodePoint > 0) {
+ codePoints[new_len] = newCodePoint;
+ continue;
+ }
+ }
+ codePoints[new_len] = codePoint;
+ }
+ return new String(codePoints, 0, new_len);
+ }
+
+ /**
+ * Returns vendor specific Unicode corresponding to the Unicode AndroidPua.
+ *
+ * @param pua Unicode PUA for Android,
+ * @return vendor specific sjis, or -1 if there's no map for the AndroidPua.
+ */
+ public int getVendorSpecificPuaFromAndroidPua(int pua) {
+ return nativeGetVendorSpecificPuaFromAndroidPua(mNativeEmojiFactory, pua);
+ }
+
+ public String getVendorSpecificPuaFromAndroidPua(String puaString) {
+ if (puaString == null) {
+ return null;
+ }
+ int minVsp = nativeGetMinimumAndroidPua(mNativeEmojiFactory);
+ int maxVsp = nativeGetMaximumAndroidPua(mNativeEmojiFactory);
+ int len = puaString.length();
+ int[] codePoints = new int[puaString.codePointCount(0, len)];
+
+ int new_len = 0;
+ for (int i = 0; i < len; i = puaString.offsetByCodePoints(i, 1), new_len++) {
+ int codePoint = puaString.codePointAt(i);
+ if (minVsp <= codePoint && codePoint <= maxVsp) {
+ int newCodePoint = getVendorSpecificPuaFromAndroidPua(codePoint);
+ if (newCodePoint > 0) {
+ codePoints[new_len] = newCodePoint;
+ continue;
+ }
+ }
+ codePoints[new_len] = codePoint;
+ }
+ return new String(codePoints, 0, new_len);
+ }
+
+ /**
+ * Constructs an instance of EmojiFactory corresponding to the name.
+ *
+ * @param class_name Name of the factory. This must include complete package name.
+ * @return A concrete EmojiFactory instance corresponding to factory_name.
+ * If factory_name is invalid, null is returned.
+ */
+ public static native EmojiFactory newInstance(String class_name);
+
+ /**
+ * Constructs an instance of available EmojiFactory.
+ *
+ * @return A concrete EmojiFactory instance. If there are several available
+ * EmojiFactory class, preferred one is chosen by the system. If there isn't, null
+ * is returned.
+ */
+ public static native EmojiFactory newAvailableInstance();
+
+ // native methods
+
+ private native void nativeDestructor(int factory);
+ private native Bitmap nativeGetBitmapFromAndroidPua(int nativeEmojiFactory, int AndroidPua);
+ private native int nativeGetAndroidPuaFromVendorSpecificSjis(int nativeEmojiFactory,
+ char sjis);
+ private native int nativeGetVendorSpecificSjisFromAndroidPua(int nativeEmojiFactory,
+ int pua);
+ private native int nativeGetAndroidPuaFromVendorSpecificPua(int nativeEmojiFactory,
+ int vsp);
+ private native int nativeGetVendorSpecificPuaFromAndroidPua(int nativeEmojiFactory,
+ int pua);
+ private native int nativeGetMaximumVendorSpecificPua(int nativeEmojiFactory);
+ private native int nativeGetMinimumVendorSpecificPua(int nativeEmojiFactory);
+ private native int nativeGetMaximumAndroidPua(int nativeEmojiFactory);
+ private native int nativeGetMinimumAndroidPua(int nativeEmojiFactory);
+}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index f1e613e..34d5695 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1377,9 +1377,11 @@ public class InputMethodService extends AbstractInputMethodService {
if (mExtractedToken != token) {
return;
}
- if (mExtractEditText != null && text != null) {
- mExtractedText = text;
- mExtractEditText.setExtractedText(text);
+ if (text != null) {
+ if (mExtractEditText != null) {
+ mExtractedText = text;
+ mExtractEditText.setExtractedText(text);
+ }
}
}
diff --git a/core/java/android/provider/Checkin.java b/core/java/android/provider/Checkin.java
index 1454089..d11a9c5 100644
--- a/core/java/android/provider/Checkin.java
+++ b/core/java/android/provider/Checkin.java
@@ -132,8 +132,6 @@ public final class Checkin {
BROWSER_SNAP_CENTER,
BROWSER_TEXT_SIZE_CHANGE,
BROWSER_ZOOM_OVERVIEW,
- BROWSER_ZOOM_RING,
- BROWSER_ZOOM_RING_DRAG,
CRASHES_REPORTED,
CRASHES_TRUNCATED,
ELAPSED_REALTIME_SEC,
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
index 87153cf..6f5513a 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothDeviceService.java
@@ -237,7 +237,28 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
public void run() {
boolean res = (enableNative() == 0);
if (res) {
- mEventLoop.start();
+ int retryCount = 2;
+ boolean running = false;
+ while ((retryCount-- > 0) && !running) {
+ mEventLoop.start();
+ // it may take a momement for the other thread to do its
+ // thing. Check periodically for a while.
+ int pollCount = 5;
+ while ((pollCount-- > 0) && !running) {
+ if (mEventLoop.isEventLoopRunning()) {
+ running = true;
+ break;
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {}
+ }
+ }
+ if (!running) {
+ log("bt EnableThread giving up");
+ res = false;
+ disableNative();
+ }
}
if (mEnableCallback != null) {
@@ -254,14 +275,20 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
persistBluetoothOnSetting(true);
}
mIsDiscovering = false;
- Intent intent = new Intent(BluetoothIntent.ENABLED_ACTION);
mBondState.loadBondState();
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mHandler.sendMessageDelayed(mHandler.obtainMessage(REGISTER_SDP_RECORDS), 3000);
// Update mode
mEventLoop.onModeChanged(getModeNative());
}
+ Intent intent = null;
+ if (res) {
+ intent = new Intent(BluetoothIntent.ENABLED_ACTION);
+ } else {
+ intent = new Intent(BluetoothIntent.DISABLED_ACTION);
+ }
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+
mEnableThread = null;
}
}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 8b09583..e4ebcca 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -44,6 +44,7 @@ class BluetoothEventLoop {
private int mNativeData;
private Thread mThread;
+ private boolean mStarted;
private boolean mInterrupted;
private HashMap<String, Integer> mPasskeyAgentRequestData;
private HashMap<String, IBluetoothDeviceCallback> mGetRemoteServiceChannelCallbacks;
@@ -122,14 +123,18 @@ class BluetoothEventLoop {
public void run() {
try {
if (setUpEventLoopNative()) {
+ mStarted = true;
while (!mInterrupted) {
waitForAndDispatchEvent(0);
sleep(500);
}
- tearDownEventLoopNative();
}
+ // tear down even in the error case to clean
+ // up anything we started to setup
+ tearDownEventLoopNative();
} catch (InterruptedException e) { }
if (DBG) log("Event Loop thread finished");
+ mThread = null;
}
};
if (DBG) log("Starting Event Loop thread");
@@ -152,7 +157,7 @@ class BluetoothEventLoop {
}
public synchronized boolean isEventLoopRunning() {
- return mThread != null;
+ return mThread != null && mStarted;
}
/*package*/ void onModeChanged(String bluezMode) {
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 8aa49af..17c7a6c 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -204,7 +204,7 @@ implements MovementMethod
MotionEvent event) {
boolean handled = Touch.onTouchEvent(widget, buffer, event);
- if (widget.isFocused() && !widget.didTouchFocusSelectAll()) {
+ if (widget.isFocused() && !widget.didTouchFocusSelect()) {
if (event.getAction() == MotionEvent.ACTION_UP) {
int x = (int) event.getX();
int y = (int) event.getY();
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index 39ad976..61ec67f 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -159,13 +159,21 @@ public abstract class MetaKeyKeyListener {
/**
* Returns true if this object is one that this class would use to
- * keep track of meta state in the specified text.
+ * keep track of any meta state in the specified text.
*/
public static boolean isMetaTracker(CharSequence text, Object what) {
return what == CAP || what == ALT || what == SYM ||
what == SELECTING;
}
+ /**
+ * Returns true if this object is one that this class would use to
+ * keep track of the selecting meta state in the specified text.
+ */
+ public static boolean isSelectingMetaTracker(CharSequence text, Object what) {
+ return what == SELECTING;
+ }
+
private static void adjust(Spannable content, Object what) {
int current = content.getSpanFlags(what);
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 88ff3c5..f7ac522 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -498,7 +498,6 @@ public class GestureDetector {
if (mIsDoubleTapping) {
// Finally, give the up event of the double-tap
handled |= mDoubleTapListener.onDoubleTapEvent(ev);
- mIsDoubleTapping = false;
} else if (mInLongPress) {
mHandler.removeMessages(TAP);
mInLongPress = false;
@@ -520,6 +519,7 @@ public class GestureDetector {
mPreviousUpEvent = MotionEvent.obtain(ev);
mVelocityTracker.recycle();
mVelocityTracker = null;
+ mIsDoubleTapping = false;
mHandler.removeMessages(SHOW_PRESS);
mHandler.removeMessages(LONG_PRESS);
break;
@@ -529,6 +529,7 @@ public class GestureDetector {
mHandler.removeMessages(TAP);
mVelocityTracker.recycle();
mVelocityTracker = null;
+ mIsDoubleTapping = false;
mStillDown = false;
if (mInLongPress) {
mInLongPress = false;
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index cc3563c..841066c 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -26,9 +26,6 @@ public class HapticFeedbackConstants {
public static final int LONG_PRESS = 0;
- /** @hide pending API council */
- public static final int ZOOM_RING_TICK = 1;
-
/**
* Flag for {@link View#performHapticFeedback(int, int)
* View.performHapticFeedback(int, int)}: Ignore the setting in the
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3e762f5..d78320a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3663,8 +3663,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* would make sense to automatically display a soft input window for
* it. Subclasses should override this if they implement
* {@link #onCreateInputConnection(EditorInfo)} to return true if
- * a call on that method would return a non-null InputConnection. The
- * default implementation always returns false.
+ * a call on that method would return a non-null InputConnection, and
+ * they are really a first-class editor that the user would normally
+ * start typing on when the go into a window containing your view.
+ *
+ * <p>The default implementation always returns false. This does
+ * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)}
+ * will not be called or the user can not otherwise perform edits on your
+ * view; it is just a hint to the system that this is not the primary
+ * purpose of this view.
*
* @return Returns true if this view is a text editor, else false.
*/
@@ -3689,6 +3696,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
/**
+ * Called by the {@link android.view.inputmethod.InputMethodManager}
+ * when a view who is not the current
+ * input connection target is trying to make a call on the manager. The
+ * default implementation returns false; you can override this to return
+ * true for certain views if you are performing InputConnection proxying
+ * to them.
+ * @param view The View that is making the InputMethodManager call.
+ * @return Return true to allow the call, false to reject.
+ */
+ public boolean checkInputConnectionProxy(View view) {
+ return false;
+ }
+
+ /**
* Show the context menu for this view. It is not safe to hold on to the
* menu after returning from this method.
*
@@ -5016,7 +5037,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
(viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL ?
getVerticalScrollbarWidth() : 0;
- scrollBar.setBounds(scrollX + (mPaddingLeft & inside) + getScrollBarPaddingLeft(), top,
+ scrollBar.setBounds(scrollX + (mPaddingLeft & inside), top,
scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap, top + size);
scrollBar.setParameters(
computeHorizontalScrollRange(),
@@ -6503,32 +6524,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
return mBGDrawable;
}
- private int getScrollBarPaddingLeft() {
- // TODO: Deal with RTL languages
- return 0;
- }
-
- /*
- * Returns the pixels occupied by the vertical scrollbar, if not overlaid
- */
- private int getScrollBarPaddingRight() {
- // TODO: Deal with RTL languages
- if ((mViewFlags & SCROLLBARS_VERTICAL) == 0) {
- return 0;
- }
- return (mViewFlags & SCROLLBARS_INSET_MASK) == 0 ? 0 : getVerticalScrollbarWidth();
- }
-
- /*
- * Returns the pixels occupied by the horizontal scrollbar, if not overlaid
- */
- private int getScrollBarPaddingBottom() {
- if ((mViewFlags & SCROLLBARS_HORIZONTAL) == 0) {
- return 0;
- }
- return (mViewFlags & SCROLLBARS_INSET_MASK) == 0 ? 0 : getHorizontalScrollbarHeight();
- }
-
/**
* Sets the padding. The view may add on the space required to display
* the scrollbars, depending on the style and visibility of the scrollbars.
@@ -6552,7 +6547,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
mUserPaddingRight = right;
mUserPaddingBottom = bottom;
- if (mPaddingLeft != left + getScrollBarPaddingLeft()) {
+ final int viewFlags = mViewFlags;
+
+ // Common case is there are no scroll bars.
+ if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) {
+ // TODO: Deal with RTL languages to adjust left padding instead of right.
+ if ((viewFlags & SCROLLBARS_VERTICAL) != 0) {
+ right += (viewFlags & SCROLLBARS_INSET_MASK) == 0
+ ? 0 : getVerticalScrollbarWidth();
+ }
+ if ((viewFlags & SCROLLBARS_HORIZONTAL) == 0) {
+ bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0
+ ? 0 : getHorizontalScrollbarHeight();
+ }
+ }
+
+ if (mPaddingLeft != left) {
changed = true;
mPaddingLeft = left;
}
@@ -6560,13 +6570,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
changed = true;
mPaddingTop = top;
}
- if (mPaddingRight != right + getScrollBarPaddingRight()) {
+ if (mPaddingRight != right) {
changed = true;
- mPaddingRight = right + getScrollBarPaddingRight();
+ mPaddingRight = right;
}
- if (mPaddingBottom != bottom + getScrollBarPaddingBottom()) {
+ if (mPaddingBottom != bottom) {
changed = true;
- mPaddingBottom = bottom + getScrollBarPaddingBottom();
+ mPaddingBottom = bottom;
}
if (changed) {
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 52b4107..deca910 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -386,7 +386,14 @@ public class BaseInputConnection implements InputConnection {
// anyway.
return true;
}
- Selection.setSelection(content, start, end);
+ if (start == end && MetaKeyKeyListener.getMetaState(content,
+ MetaKeyKeyListener.META_SELECTING) != 0) {
+ // If we are in selection mode, then we want to extend the
+ // selection instead of replacing it.
+ Selection.extendSelection(content, start);
+ } else {
+ Selection.setSelection(content, start, end);
+ }
return true;
}
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 1c0d42a..b00e565 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -33,43 +33,49 @@ public class EditorInfo implements InputType, Parcelable {
public static final int IME_MASK_ACTION = 0x000000ff;
/**
- * Bits of {@link #IME_MASK_ACTION}: there is no special action
- * associated with this editor.
+ * Bits of {@link #IME_MASK_ACTION}: no specific action has been
+ * associated with this editor, let the editor come up with its own if
+ * it can.
*/
- public static final int IME_ACTION_NONE = 0x00000000;
+ public static final int IME_ACTION_UNSPECIFIED = 0x00000000;
+
+ /**
+ * Bits of {@link #IME_MASK_ACTION}: there is no available action.
+ */
+ public static final int IME_ACTION_NONE = 0x00000001;
/**
* Bits of {@link #IME_MASK_ACTION}: the action key performs a "go"
* operation to take the user to the target of the text they typed.
* Typically used, for example, when entering a URL.
*/
- public static final int IME_ACTION_GO = 0x00000001;
+ public static final int IME_ACTION_GO = 0x00000002;
/**
* Bits of {@link #IME_MASK_ACTION}: the action key performs a "search"
* operation, taking the user to the results of searching for the text
* the have typed (in whatever context is appropriate).
*/
- public static final int IME_ACTION_SEARCH = 0x00000002;
+ public static final int IME_ACTION_SEARCH = 0x00000003;
/**
* Bits of {@link #IME_MASK_ACTION}: the action key performs a "send"
* operation, delivering the text to its target. This is typically used
* when composing a message.
*/
- public static final int IME_ACTION_SEND = 0x00000003;
+ public static final int IME_ACTION_SEND = 0x00000004;
/**
* Bits of {@link #IME_MASK_ACTION}: the action key performs a "next"
* operation, taking the user to the next field that will accept text.
*/
- public static final int IME_ACTION_NEXT = 0x00000004;
+ public static final int IME_ACTION_NEXT = 0x00000005;
/**
* Bits of {@link #IME_MASK_ACTION}: the action key performs a "done"
* operation, typically meaning the IME will be closed.
*/
- public static final int IME_ACTION_DONE = 0x00000005;
+ public static final int IME_ACTION_DONE = 0x00000006;
/**
* Flag of {@link #imeOptions}: used in conjunction with
@@ -82,21 +88,15 @@ public class EditorInfo implements InputType, Parcelable {
public static final int IME_FLAG_NO_ENTER_ACTION = 0x40000000;
/**
- * Generic non-special type for {@link #imeOptions}.
- */
- public static final int IME_NORMAL = 0x00000000;
-
- /**
- * Special code for when the ime option has been undefined. This is not
- * used with the EditorInfo structure, but can be used elsewhere.
+ * Generic unspecified type for {@link #imeOptions}.
*/
- public static final int IME_UNDEFINED = 0x80000000;
+ public static final int IME_NULL = 0x00000000;
/**
* Extended type information for the editor, to help the IME better
* integrate with it.
*/
- public int imeOptions = IME_NORMAL;
+ public int imeOptions = IME_NULL;
/**
* A string supplying additional information options that are
diff --git a/core/java/android/view/inputmethod/ExtractedText.java b/core/java/android/view/inputmethod/ExtractedText.java
index e5d3cae..c2851d6 100644
--- a/core/java/android/view/inputmethod/ExtractedText.java
+++ b/core/java/android/view/inputmethod/ExtractedText.java
@@ -55,6 +55,11 @@ public class ExtractedText implements Parcelable {
public static final int FLAG_SINGLE_LINE = 0x0001;
/**
+ * Bit for {@link #flags}: set if the editor is currently in selection mode.
+ */
+ public static final int FLAG_SELECTING = 0x0002;
+
+ /**
* Additional bit flags of information about the edited text.
*/
public int flags;
@@ -72,7 +77,7 @@ public class ExtractedText implements Parcelable {
dest.writeInt(partialEndOffset);
dest.writeInt(selectionStart);
dest.writeInt(selectionEnd);
- dest.writeInt(flags);
+ dest.writeInt(this.flags);
}
/**
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 32cce35..8b6831e 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -17,7 +17,6 @@
package android.view.inputmethod;
import android.os.Bundle;
-import android.text.Spanned;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -135,7 +134,7 @@ public interface InputConnection {
* @return Returns true on success, false if the input connection is no longer
* valid.
*/
- boolean deleteSurroundingText(int leftLength, int rightLength);
+ public boolean deleteSurroundingText(int leftLength, int rightLength);
/**
* Set composing text around the current cursor position with the given text,
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
new file mode 100644
index 0000000..e3d5e62
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007-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 android.view.inputmethod;
+
+import android.os.Bundle;
+import android.view.KeyEvent;
+
+/**
+ * <p>Wrapper class for proxying calls to another InputConnection. Subclass
+ * and have fun!
+ */
+public class InputConnectionWrapper implements InputConnection {
+ private final InputConnection mTarget;
+
+ public InputConnectionWrapper(InputConnection target) {
+ mTarget = target;
+ }
+
+ public CharSequence getTextBeforeCursor(int n, int flags) {
+ return mTarget.getTextBeforeCursor(n, flags);
+ }
+
+ public CharSequence getTextAfterCursor(int n, int flags) {
+ return mTarget.getTextAfterCursor(n, flags);
+ }
+
+ public int getCursorCapsMode(int reqModes) {
+ return mTarget.getCursorCapsMode(reqModes);
+ }
+
+ public ExtractedText getExtractedText(ExtractedTextRequest request,
+ int flags) {
+ return mTarget.getExtractedText(request, flags);
+ }
+
+ public boolean deleteSurroundingText(int leftLength, int rightLength) {
+ return mTarget.deleteSurroundingText(leftLength, rightLength);
+ }
+
+ public boolean setComposingText(CharSequence text, int newCursorPosition) {
+ return mTarget.setComposingText(text, newCursorPosition);
+ }
+
+ public boolean finishComposingText() {
+ return mTarget.finishComposingText();
+ }
+
+ public boolean commitText(CharSequence text, int newCursorPosition) {
+ return mTarget.commitText(text, newCursorPosition);
+ }
+
+ public boolean commitCompletion(CompletionInfo text) {
+ return mTarget.commitCompletion(text);
+ }
+
+ public boolean setSelection(int start, int end) {
+ return mTarget.setSelection(start, end);
+ }
+
+ public boolean performEditorAction(int editorAction) {
+ return mTarget.performEditorAction(editorAction);
+ }
+
+ public boolean performContextMenuAction(int id) {
+ return mTarget.performContextMenuAction(id);
+ }
+
+ public boolean beginBatchEdit() {
+ return mTarget.beginBatchEdit();
+ }
+
+ public boolean endBatchEdit() {
+ return mTarget.endBatchEdit();
+ }
+
+ public boolean sendKeyEvent(KeyEvent event) {
+ return mTarget.sendKeyEvent(event);
+ }
+
+ public boolean clearMetaKeyStates(int states) {
+ return mTarget.clearMetaKeyStates(states);
+ }
+
+ public boolean reportFullscreenMode(boolean enabled) {
+ return mTarget.reportFullscreenMode(enabled);
+ }
+
+ public boolean performPrivateCommand(String action, Bundle data) {
+ return mTarget.performPrivateCommand(action, data);
+ }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 916ffea..7f2142e 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -529,7 +529,10 @@ public final class InputMethodManager {
public boolean isActive(View view) {
checkFocus();
synchronized (mH) {
- return mServedView == view && mCurrentTextBoxAttribute != null;
+ return (mServedView == view
+ || (mServedView != null
+ && mServedView.checkInputConnectionProxy(view)))
+ && mCurrentTextBoxAttribute != null;
}
}
@@ -620,7 +623,8 @@ public final class InputMethodManager {
public void displayCompletions(View view, CompletionInfo[] completions) {
checkFocus();
synchronized (mH) {
- if (mServedView != view) {
+ if (mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view))) {
return;
}
@@ -637,7 +641,8 @@ public final class InputMethodManager {
public void updateExtractedText(View view, int token, ExtractedText text) {
checkFocus();
synchronized (mH) {
- if (mServedView != view) {
+ if (mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view))) {
return;
}
@@ -730,7 +735,8 @@ public final class InputMethodManager {
ResultReceiver resultReceiver) {
checkFocus();
synchronized (mH) {
- if (mServedView != view) {
+ if (mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view))) {
return false;
}
@@ -871,7 +877,8 @@ public final class InputMethodManager {
public void restartInput(View view) {
checkFocus();
synchronized (mH) {
- if (mServedView != view) {
+ if (mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view))) {
return;
}
@@ -1032,7 +1039,7 @@ public final class InputMethodManager {
if (DEBUG) Log.v(TAG, "focusOut: " + view
+ " mServedView=" + mServedView
+ " winFocus=" + view.hasWindowFocus());
- if (mServedView == view) {
+ if (mServedView != view) {
// The following code would auto-hide the IME if we end up
// with no more views with focus. This can happen, however,
// whenever we go into touch mode, so it ends up hiding
@@ -1129,8 +1136,9 @@ public final class InputMethodManager {
try {
final boolean isTextEditor = focusedView != null &&
focusedView.onCheckIsTextEditor();
- mService.windowGainedFocus(mClient, focusedView != null,
- isTextEditor, softInputMode, first, windowFlags);
+ mService.windowGainedFocus(mClient, rootView.getWindowToken(),
+ focusedView != null, isTextEditor, softInputMode, first,
+ windowFlags);
} catch (RemoteException e) {
}
}
@@ -1150,8 +1158,9 @@ public final class InputMethodManager {
int candidatesStart, int candidatesEnd) {
checkFocus();
synchronized (mH) {
- if (mServedView != view || mCurrentTextBoxAttribute == null
- || mCurMethod == null) {
+ if ((mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view)))
+ || mCurrentTextBoxAttribute == null || mCurMethod == null) {
return;
}
@@ -1189,8 +1198,9 @@ public final class InputMethodManager {
public void updateCursor(View view, int left, int top, int right, int bottom) {
checkFocus();
synchronized (mH) {
- if (mServedView != view || mCurrentTextBoxAttribute == null
- || mCurMethod == null) {
+ if ((mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view)))
+ || mCurrentTextBoxAttribute == null || mCurMethod == null) {
return;
}
@@ -1223,7 +1233,8 @@ public final class InputMethodManager {
public void sendAppPrivateCommand(View view, String action, Bundle data) {
checkFocus();
synchronized (mH) {
- if ((view != null && mServedView != view)
+ if ((mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view)))
|| mCurrentTextBoxAttribute == null || mCurMethod == null) {
return;
}
diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java
index 39806dc..efc131f 100644
--- a/core/java/android/webkit/TextDialog.java
+++ b/core/java/android/webkit/TextDialog.java
@@ -32,8 +32,6 @@ import android.text.Spannable;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.MovementMethod;
-import android.text.method.PasswordTransformationMethod;
-import android.text.method.TextKeyListener;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.KeyCharacterMap;
@@ -475,15 +473,10 @@ import java.util.ArrayList;
* @param inPassword True if the textfield is a password field.
*/
/* package */ void setInPassword(boolean inPassword) {
- PasswordTransformationMethod method;
if (inPassword) {
- method = PasswordTransformationMethod.getInstance();
- setInputType(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.
+ setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.
TYPE_TEXT_VARIATION_PASSWORD);
- } else {
- method = null;
}
- setTransformationMethod(method);
}
/* package */ void setMaxLength(int maxLength) {
@@ -545,20 +538,13 @@ import java.util.ArrayList;
* removing the password input type.
*/
public void setSingleLine(boolean single) {
- if (mSingle != single) {
- TextKeyListener.Capitalize cap;
- int inputType = EditorInfo.TYPE_CLASS_TEXT;
- if (single) {
- cap = TextKeyListener.Capitalize.NONE;
- } else {
- cap = TextKeyListener.Capitalize.SENTENCES;
- inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
- }
- setKeyListener(TextKeyListener.getInstance(!single, cap));
- mSingle = single;
- setHorizontallyScrolling(single);
- setInputType(inputType);
+ int inputType = EditorInfo.TYPE_CLASS_TEXT;
+ if (!single) {
+ inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
}
+ mSingle = single;
+ setHorizontallyScrolling(single);
+ setInputType(inputType);
}
/**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 91795a3..dc39b90 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -73,7 +73,6 @@ import android.widget.Scroller;
import android.widget.Toast;
import android.widget.ZoomButtonsController;
import android.widget.ZoomControls;
-import android.widget.ZoomRingController;
import android.widget.FrameLayout;
import android.widget.AdapterView.OnItemClickListener;
@@ -239,8 +238,8 @@ public class WebView extends AbsoluteLayout
*/
VelocityTracker mVelocityTracker;
- private static boolean mShowZoomRingTutorial = true;
- private static final int ZOOM_RING_TUTORIAL_DURATION = 3000;
+ private static boolean mShowZoomTutorial = true;
+ private static final int ZOOM_TUTORIAL_DURATION = 3000;
/**
* Touch mode
@@ -265,11 +264,6 @@ public class WebView extends AbsoluteLayout
// Whether to forward the touch events to WebCore
private boolean mForwardTouchEvents = false;
- // Whether we are in the drag tap mode, which exists starting at the second
- // tap's down, through its move, and includes its up. These events should be
- // given to the method on the zoom controller.
- private boolean mInZoomTapDragMode = false;
-
// Whether to prevent drag during touch. The initial value depends on
// mForwardTouchEvents. If WebCore wants touch events, we assume it will
// take control of touch events unless it says no for touch down event.
@@ -361,7 +355,7 @@ public class WebView extends AbsoluteLayout
private static final int UPDATE_TEXT_ENTRY_ADAPTER = 6;
private static final int SWITCH_TO_ENTER = 7;
private static final int RESUME_WEBCORE_UPDATE = 8;
- private static final int DISMISS_ZOOM_RING_TUTORIAL = 9;
+ private static final int DISMISS_ZOOM_TUTORIAL = 9;
//! arg1=x, arg2=y
static final int SCROLL_TO_MSG_ID = 10;
@@ -417,11 +411,6 @@ public class WebView extends AbsoluteLayout
// width which view is considered to be fully zoomed out
static final int ZOOM_OUT_WIDTH = 1024;
- private static final float MAX_ZOOM_RING_ANGLE = (float) (Math.PI * 2 / 3);
- private static final int ZOOM_RING_STEPS = 4;
- private static final float ZOOM_RING_ANGLE_UNIT = MAX_ZOOM_RING_ANGLE
- / ZOOM_RING_STEPS;
-
private static final float DEFAULT_MAX_ZOOM_SCALE = 2;
private static final float DEFAULT_MIN_ZOOM_SCALE = (float) 1/3;
// scale limit, which can be set through viewport meta tag in the web page
@@ -560,146 +549,52 @@ public class WebView extends AbsoluteLayout
}
private ZoomButtonsController mZoomButtonsController;
+ private ImageView mZoomOverviewButton;
- private ZoomRingController mZoomRingController;
- private ImageView mZoomRingOverview;
- private Animation mZoomRingOverviewExitAnimation;
-
- // These keep track of the center point of the zoom ring. They are used to
+ // These keep track of the center point of the zoom. They are used to
// determine the point around which we should zoom.
private float mZoomCenterX;
private float mZoomCenterY;
- private ZoomRingController.OnZoomListener mZoomListener =
- new ZoomRingController.OnZoomListener() {
-
- private float mClockwiseBound;
- private float mCounterClockwiseBound;
- private float mStartScale;
+ private ZoomButtonsController.OnZoomListener mZoomListener =
+ new ZoomButtonsController.OnZoomListener() {
public void onCenter(int x, int y) {
// Don't translate when the control is invoked, hence we do nothing
// in this callback
}
- public void onBeginPan() {
- setZoomOverviewVisible(false);
+ public void onOverview() {
+ mZoomButtonsController.setVisible(false);
+ zoomScrollOut();
if (mLogEvent) {
Checkin.updateStats(mContext.getContentResolver(),
- Checkin.Stats.Tag.BROWSER_ZOOM_RING_DRAG, 1, 0.0);
+ Checkin.Stats.Tag.BROWSER_ZOOM_OVERVIEW, 1, 0.0);
}
}
- public boolean onPan(int deltaX, int deltaY) {
- return pinScrollBy(deltaX, deltaY, false, 0);
- }
-
- public void onEndPan() {
- }
-
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 && mClockwiseBound < (float) (2 * Math.PI)) {
- angle = -(float) Math.round(ZOOM_RING_STEPS
- * (mActualScale - 1) / (mMaxZoomScale - 1))
- / ZOOM_RING_STEPS;
- } else if (mActualScale < 1 && mCounterClockwiseBound > 0) {
- angle = (float) Math.round(ZOOM_RING_STEPS
- * (1 - mActualScale) / (1 - mMinZoomScale))
- / ZOOM_RING_STEPS;
- }
- mZoomRingController.setThumbAngle(angle * MAX_ZOOM_RING_ANGLE);
-
- // Don't show a thumb if the user cannot zoom
- mZoomRingController.setThumbVisible(mMinZoomScale != mMaxZoomScale);
-
- // 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);
- }
+ mZoomButtonsController.setOverviewVisible(true);
+ updateButtonsEnabled();
}
}
- 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);
+ private void updateButtonsEnabled() {
+ mZoomButtonsController.setZoomInEnabled(mActualScale < mMaxZoomScale);
+ mZoomButtonsController.setZoomOutEnabled(mActualScale > mMinZoomScale);
}
- public boolean onDragZoom(int deltaZoomLevel, int centerX,
- int centerY, float startAngle, float curAngle) {
- if (deltaZoomLevel < 0
- && Math.abs(mActualScale - mMinZoomScale) < 0.01f
- || deltaZoomLevel > 0
- && Math.abs(mActualScale - mMaxZoomScale) < 0.01f
- || deltaZoomLevel == 0) {
- return false;
- }
- mZoomCenterX = (float) centerX;
- mZoomCenterY = (float) centerY;
-
- float scale = 1.0f;
- // 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 <= mClockwiseBound) {
- scale = mMaxZoomScale;
- } else {
- scale = 1 + (float) Math.round(
- ((float) 2 * Math.PI - curAngle)
- / ZOOM_RING_ANGLE_UNIT) / ZOOM_RING_STEPS
- * (mMaxZoomScale - 1);
- }
- }
- zoomWithPreview(scale);
- return true;
- }
-
- public void onSimpleZoom(boolean zoomIn, int centerX, int centerY) {
- mZoomCenterX = (float) centerX;
- mZoomCenterY = (float) centerY;
-
+ public void onZoom(boolean zoomIn) {
if (zoomIn) {
zoomIn();
} else {
zoomOut();
}
+
+ updateButtonsEnabled();
}
-
};
/**
@@ -738,34 +633,8 @@ public class WebView extends AbsoluteLayout
mFocusData.mX = 0;
mFocusData.mY = 0;
mScroller = new Scroller(context);
- mZoomRingController = new ZoomRingController(context, this);
- mZoomRingController.setCallback(mZoomListener);
- mZoomRingController.setTrackDrawable(
- com.android.internal.R.drawable.zoom_ring_track_absolute);
- float density = context.getResources().getDisplayMetrics().density;
- mZoomRingController.setPannerAcceleration((int) (160 * density));
- mZoomRingController.setPannerStartAcceleratingDuration((int) (700 * density));
- createZoomRingOverviewTab();
mZoomButtonsController = new ZoomButtonsController(context, this);
- mZoomButtonsController.setOverviewVisible(true);
- mZoomButtonsController.setCallback(new ZoomButtonsController.OnZoomListener() {
- public void onCenter(int x, int y) {
- mZoomListener.onCenter(x, y);
- }
-
- public void onOverview() {
- mZoomButtonsController.setVisible(false);
- zoomScrollOut();
- }
-
- public void onVisibilityChanged(boolean visible) {
- mZoomListener.onVisibilityChanged(visible);
- }
-
- public void onZoom(boolean zoomIn) {
- mZoomListener.onSimpleZoom(zoomIn, getWidth() / 2, getHeight() / 2);
- }
- });
+ mZoomButtonsController.setCallback(mZoomListener);
}
private void init() {
@@ -783,67 +652,6 @@ public class WebView extends AbsoluteLayout
mDoubleTapSlopSquare = doubleTapslop * doubleTapslop;
}
- private void createZoomRingOverviewTab() {
- Context context = getContext();
-
- mZoomRingOverviewExitAnimation = AnimationUtils.loadAnimation(context,
- com.android.internal.R.anim.fade_out);
-
- mZoomRingOverview = new ImageView(context);
- mZoomRingOverview.setBackgroundResource(
- com.android.internal.R.drawable.zoom_ring_overview_tab);
- mZoomRingOverview.setImageResource(com.android.internal.R.drawable.btn_zoom_page);
-
- FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- FrameLayout.LayoutParams.WRAP_CONTENT,
- Gravity.CENTER);
- // TODO: magic constant that's based on the zoom ring radius + some offset
- lp.topMargin = 200;
- mZoomRingOverview.setLayoutParams(lp);
- mZoomRingOverview.setOnClickListener(new View.OnClickListener() {
- 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();
- }});
-
- // Measure the overview View to figure out its height
- mZoomRingOverview.forceLayout();
- mZoomRingOverview.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-
- ViewGroup container = mZoomRingController.getContainer();
- // Find the index of the zoom ring in the container
- View zoomRing = container.findViewById(mZoomRingController.getZoomRingId());
- int zoomRingIndex;
- for (zoomRingIndex = container.getChildCount() - 1; zoomRingIndex >= 0; zoomRingIndex--) {
- if (container.getChildAt(zoomRingIndex) == zoomRing) break;
- }
- // Add the overview tab below the zoom ring (so we don't steal its events)
- container.addView(mZoomRingOverview, zoomRingIndex);
- // Since we use margins to adjust the vertical placement of the tab, the widget
- // ends up getting clipped off. Ensure the container is big enough for
- // us.
- int myHeight = mZoomRingOverview.getMeasuredHeight() + lp.topMargin / 2;
- // Multiplied by 2 b/c the zoom ring needs to be centered on the screen
- container.setMinimumHeight(myHeight * 2);
- }
-
- private void setZoomOverviewVisible(boolean visible) {
- int newVisibility = visible ? View.VISIBLE : View.INVISIBLE;
- if (mZoomRingOverview.getVisibility() == newVisibility) return;
-
- if (!visible) {
- mZoomRingOverview.startAnimation(mZoomRingOverviewExitAnimation);
- }
- mZoomRingOverview.setVisibility(newVisibility);
- }
-
/* package */ boolean onSavePassword(String schemePlusHost, String username,
String password, final Message resumeMsg) {
boolean rVal = false;
@@ -2988,6 +2796,7 @@ public class WebView extends AbsoluteLayout
* @param end End of selection to delete.
*/
/* package */ void deleteSelection(int start, int end) {
+ mTextGeneration++;
mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end,
new WebViewCore.FocusData(mFocusData));
}
@@ -3452,8 +3261,7 @@ public class WebView extends AbsoluteLayout
p.setOnHierarchyChangeListener(null);
}
- // Clean up the zoom ring
- mZoomRingController.setVisible(false);
+ // Clean up the zoom controller
mZoomButtonsController.setVisible(false);
}
@@ -3565,9 +3373,7 @@ public class WebView extends AbsoluteLayout
@Override
protected void onSizeChanged(int w, int h, int ow, int oh) {
super.onSizeChanged(w, h, ow, oh);
- // Center zooming to the center of the screen. This is appropriate for
- // this case of zooming, and it also sets us up properly if we remove
- // the new zoom ring controller
+ // Center zooming to the center of the screen.
mZoomCenterX = getViewWidth() * .5f;
mZoomCenterY = getViewHeight() * .5f;
@@ -3641,13 +3447,13 @@ public class WebView extends AbsoluteLayout
return false;
}
- if (mShowZoomRingTutorial && getSettings().supportZoom()
- && (mMaxZoomScale - mMinZoomScale) > ZOOM_RING_STEPS * 0.01f) {
- ZoomRingController.showZoomTutorialOnce(mContext);
- mShowZoomRingTutorial = false;
+ if (mShowZoomTutorial && getSettings().supportZoom()
+ && (mMaxZoomScale != mMinZoomScale)) {
+ ZoomButtonsController.showZoomTutorialOnce(mContext);
+ mShowZoomTutorial = false;
mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(DISMISS_ZOOM_RING_TUTORIAL),
- ZOOM_RING_TUTORIAL_DURATION);
+ .obtainMessage(DISMISS_ZOOM_TUTORIAL),
+ ZOOM_TUTORIAL_DURATION);
}
if (LOGV_ENABLED) {
@@ -3655,15 +3461,6 @@ public class WebView extends AbsoluteLayout
+ mTouchMode);
}
- if ((mZoomRingController.isVisible() || mZoomButtonsController.isVisible())
- && mInZoomTapDragMode) {
- if (ev.getAction() == MotionEvent.ACTION_UP) {
- // Just released the second tap, no longer in tap-drag mode
- mInZoomTapDragMode = false;
- }
- return mZoomRingController.handleDoubleTapEvent(ev);
- }
-
int action = ev.getAction();
float x = ev.getX();
float y = ev.getY();
@@ -3689,7 +3486,7 @@ public class WebView extends AbsoluteLayout
WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
ted.mAction = action;
ted.mX = viewToContent((int) x + mScrollX);
- ted.mY = viewToContent((int) y + mScrollY);;
+ ted.mY = viewToContent((int) y + mScrollY);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mLastSentTouchTime = eventTime;
}
@@ -3721,7 +3518,7 @@ public class WebView extends AbsoluteLayout
nativeMoveSelection(viewToContent(mSelectX)
, viewToContent(mSelectY), false);
mTouchSelection = mExtendSelection = true;
- } else if (!ZoomRingController.useOldZoom(mContext) &&
+ } else if (!ZoomButtonsController.useOldZoom(mContext) &&
mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP) &&
(deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare)) {
// Found doubletap, invoke the zoom controller
@@ -3732,13 +3529,11 @@ public class WebView extends AbsoluteLayout
mTextEntry.updateCachedTextfield();
}
nativeClearFocus(contentX, contentY);
- mInZoomTapDragMode = true;
if (mLogEvent) {
EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION,
(eventTime - mLastTouchUpTime), eventTime);
}
- return mZoomRingController.handleDoubleTapEvent(ev) ||
- mZoomButtonsController.handleDoubleTapEvent(ev);
+ return mZoomButtonsController.handleDoubleTapEvent(ev);
} else {
mTouchMode = TOUCH_INIT_MODE;
mPreventDrag = mForwardTouchEvents;
@@ -3747,9 +3542,8 @@ public class WebView extends AbsoluteLayout
(eventTime - mLastTouchUpTime), eventTime);
}
}
- // don't trigger the link if zoom ring is visible
- if (mTouchMode == TOUCH_INIT_MODE
- && !mZoomRingController.isVisible()) {
+ // Trigger the link
+ if (mTouchMode == TOUCH_INIT_MODE) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT);
}
@@ -3885,7 +3679,7 @@ public class WebView extends AbsoluteLayout
mUserScroll = true;
}
- if (ZoomRingController.useOldZoom(mContext)) {
+ if (ZoomButtonsController.useOldZoom(mContext)) {
boolean showPlusMinus = mMinZoomScale < mMaxZoomScale;
boolean showMagnify = canZoomScrollOut();
if (mZoomControls != null && (showPlusMinus || showMagnify)) {
@@ -3909,15 +3703,6 @@ public class WebView extends AbsoluteLayout
mLastTouchUpTime = eventTime;
switch (mTouchMode) {
case TOUCH_INIT_MODE: // tap
- if (mZoomRingController.isVisible()) {
- // 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()) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
@@ -4432,14 +4217,6 @@ public class WebView extends AbsoluteLayout
}
/**
- * @hide pending API council? Assuming we make ZoomRingController itself
- * public, which I think we will.
- */
- public ZoomRingController getZoomRingController() {
- return mZoomRingController;
- }
-
- /**
* Perform zoom in in the webview
* @return TRUE if zoom in succeeds. FALSE if no zoom changes.
*/
@@ -4482,9 +4259,6 @@ public class WebView extends AbsoluteLayout
});
zoomControls.setOnZoomMagnifyClickListener(new OnClickListener() {
public void onClick(View v) {
- // Hide the zoom ring
- mZoomRingController.setVisible(false);
-
mPrivateHandler.removeCallbacks(mZoomControlRunnable);
mPrivateHandler.postDelayed(mZoomControlRunnable,
ZOOM_CONTROLS_TIMEOUT);
@@ -4693,6 +4467,7 @@ public class WebView extends AbsoluteLayout
arg.put("replace", replace);
arg.put("start", new Integer(newStart));
arg.put("end", new Integer(newEnd));
+ mTextGeneration++;
mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg);
}
@@ -5006,8 +4781,8 @@ public class WebView extends AbsoluteLayout
}
break;
- case DISMISS_ZOOM_RING_TUTORIAL:
- mZoomRingController.finishZoomTutorial();
+ case DISMISS_ZOOM_TUTORIAL:
+ mZoomButtonsController.finishZoomTutorial();
break;
default:
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d72570a..f517dc9 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -41,6 +41,10 @@ import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionWrapper;
import android.view.inputmethod.InputMethodManager;
import android.view.ContextMenu.ContextMenuInfo;
@@ -899,6 +903,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
private boolean acceptFilter() {
+ if (!mTextFilterEnabled || !(getAdapter() instanceof Filterable) ||
+ ((Filterable) getAdapter()).getFilter() == null) {
+ return false;
+ }
final Context context = mContext;
final InputMethodManager inputManager = (InputMethodManager)
context.getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -1107,7 +1115,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// filter popup needs to follow the widget.
if (mFiltered && changed && getWindowVisibility() == View.VISIBLE && mPopup != null &&
mPopup.isShowing()) {
- positionPopup(true);
+ positionPopup();
}
return changed;
@@ -2767,20 +2775,20 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// Make sure we have a window before showing the popup
if (getWindowVisibility() == View.VISIBLE) {
createTextFilter(true);
- positionPopup(false);
+ positionPopup();
// Make sure we get focus if we are showing the popup
checkFocus();
}
}
- private void positionPopup(boolean update) {
+ private void positionPopup() {
int screenHeight = getResources().getDisplayMetrics().heightPixels;
final int[] xy = new int[2];
getLocationOnScreen(xy);
// TODO: The 20 below should come from the theme and be expressed in dip
// TODO: And the gravity should be defined in the theme as well
final int bottomGap = screenHeight - xy[1] - getHeight() + (int) (mDensityScale * 20);
- if (!update) {
+ if (!mPopup.isShowing()) {
mPopup.showAtLocation(this, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL,
xy[0], bottomGap);
} else {
@@ -2849,8 +2857,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* @return True if the text filter handled the event, false otherwise.
*/
boolean sendToTextFilter(int keyCode, int count, KeyEvent event) {
- if (!mTextFilterEnabled || !(getAdapter() instanceof Filterable) ||
- ((Filterable) getAdapter()).getFilter() == null) {
+ if (!acceptFilter()) {
return false;
}
@@ -2879,7 +2886,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
break;
}
- if (okToSend && acceptFilter()) {
+ if (okToSend) {
createTextFilter(true);
KeyEvent forwardEvent = event;
@@ -2906,6 +2913,27 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
/**
+ * Return an InputConnection for editing of the filter text.
+ */
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+ // XXX we need to have the text filter created, so we can get an
+ // InputConnection to proxy to. Unfortunately this means we pretty
+ // much need to make it as soon as a list view gets focus.
+ createTextFilter(false);
+ return mTextFilter.onCreateInputConnection(outAttrs);
+ }
+
+ /**
+ * For filtering we proxy an input connection to an internal text editor,
+ * and this allows the proxying to happen.
+ */
+ @Override
+ public boolean checkInputConnectionProxy(View view) {
+ return view == mTextFilter;
+ }
+
+ /**
* Creates the window for the text filter and populates it with an EditText field;
*
* @param animateEntrance true if the window should appear with an animation
@@ -2918,6 +2946,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mTextFilter = (EditText) layoutInflater.inflate(
com.android.internal.R.layout.typing_filter, null);
+ // For some reason setting this as the "real" input type changes
+ // the text view in some way that it doesn't work, and I don't
+ // want to figure out why this is.
+ mTextFilter.setRawInputType(EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_FILTER);
mTextFilter.addTextChangedListener(this);
p.setFocusable(false);
p.setTouchable(false);
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 0a552e8..3368477 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -26,7 +26,6 @@ import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.SystemClock;
-import android.util.TypedValue;
import android.view.MotionEvent;
/**
@@ -313,12 +312,17 @@ class FastScroller {
// Non-existent letter
while (section > 0) {
section--;
- prevIndex = mSectionIndexer.getPositionForSection(section);
- if (prevIndex != index) {
- prevSection = section;
- sectionIndex = section;
- break;
- }
+ prevIndex = mSectionIndexer.getPositionForSection(section);
+ if (prevIndex != index) {
+ prevSection = section;
+ sectionIndex = section;
+ break;
+ } else if (section == 0) {
+ // When section reaches 0 here, sectionIndex must follow it.
+ // Assuming mSectionIndexer.getPositionForSection(0) == 0.
+ sectionIndex = 0;
+ break;
+ }
}
}
// Find the next index, in case the assumed next index is not
diff --git a/core/java/android/widget/Filter.java b/core/java/android/widget/Filter.java
index 1d0fd5e..7e55c78 100644
--- a/core/java/android/widget/Filter.java
+++ b/core/java/android/widget/Filter.java
@@ -42,10 +42,12 @@ public abstract class Filter {
private static final String THREAD_NAME = "Filter";
private static final int FILTER_TOKEN = 0xD0D0F00D;
private static final int FINISH_TOKEN = 0xDEADBEEF;
-
+
private Handler mThreadHandler;
private Handler mResultHandler;
+ private final Object mLock = new Object();
+
/**
* <p>Creates a new asynchronous filter.</p>
*/
@@ -81,8 +83,7 @@ public abstract class Filter {
* @see #publishResults(CharSequence, android.widget.Filter.FilterResults)
*/
public final void filter(CharSequence constraint, FilterListener listener) {
- synchronized (this) {
-
+ synchronized (mLock) {
if (mThreadHandler == null) {
HandlerThread thread = new HandlerThread(THREAD_NAME);
thread.start();
@@ -221,7 +222,7 @@ public abstract class Filter {
message.sendToTarget();
}
- synchronized (this) {
+ synchronized (mLock) {
if (mThreadHandler != null) {
Message finishMessage = mThreadHandler.obtainMessage(FINISH_TOKEN);
mThreadHandler.sendMessageDelayed(finishMessage, 3000);
@@ -229,7 +230,7 @@ public abstract class Filter {
}
break;
case FINISH_TOKEN:
- synchronized (this) {
+ synchronized (mLock) {
if (mThreadHandler != null) {
mThreadHandler.getLooper().quit();
mThreadHandler = null;
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index f2cec92..227fb95 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -451,6 +451,7 @@ public class MediaController extends FrameLayout {
public void onProgressChanged(SeekBar bar, int progress, boolean fromtouch) {
if (fromtouch) {
mDragging = true;
+ duration = mPlayer.getDuration();
long newposition = (duration * progress) / 1000L;
mPlayer.seekTo( (int) newposition);
if (mCurrentTime != null)
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3f4912f..8271a9a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -43,6 +43,7 @@ import android.text.GetChars;
import android.text.GraphicsOperations;
import android.text.ClipboardManager;
import android.text.InputFilter;
+import android.text.InputType;
import android.text.Layout;
import android.text.ParcelableSpan;
import android.text.Selection;
@@ -235,7 +236,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private CharWrapper mCharWrapper = null;
private boolean mSelectionMoved = false;
- private boolean mTouchFocusSelectedAll = false;
+ private boolean mTouchFocusSelected = false;
private Marquee mMarquee;
private boolean mRestartMarquee;
@@ -243,7 +244,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private int mMarqueeRepeatLimit = 3;
class InputContentType {
- int imeOptions = EditorInfo.IME_UNDEFINED;
+ int imeOptions = EditorInfo.IME_NULL;
String privateImeOptions;
CharSequence imeActionLabel;
int imeActionId;
@@ -261,6 +262,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final ExtractedText mTmpExtracted = new ExtractedText();
int mBatchEditNesting;
boolean mCursorChanged;
+ boolean mSelectionModeChanged;
boolean mContentChanged;
int mChangedStart, mChangedEnd, mChangedDelta;
}
@@ -287,8 +289,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @param v The view that was clicked.
* @param actionId Identifier of the action. This will be either the
- * identifier you supplied, or {@link EditorInfo#IME_UNDEFINED
- * EditorInfo.IME_UNDEFINED} if being called due to the enter key
+ * identifier you supplied, or {@link EditorInfo#IME_NULL
+ * EditorInfo.IME_NULL} if being called due to the enter key
* being pressed.
* @param event If triggered by an enter key, this is the event;
* otherwise, this is null.
@@ -1492,10 +1494,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void setPadding(int left, int top, int right, int bottom) {
- if (left != getPaddingLeft() ||
- right != getPaddingRight() ||
- top != getPaddingTop() ||
- bottom != getPaddingBottom()) {
+ if (left != mPaddingLeft ||
+ right != mPaddingRight ||
+ top != mPaddingTop ||
+ bottom != mPaddingBottom) {
nullLayouts();
}
@@ -2951,7 +2953,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
public int getImeOptions() {
return mInputContentType != null
- ? mInputContentType.imeOptions : EditorInfo.IME_UNDEFINED;
+ ? mInputContentType.imeOptions : EditorInfo.IME_NULL;
}
/**
@@ -3013,9 +3015,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* Called when an attached input method calls
* {@link InputConnection#performEditorAction(int)
* InputConnection.performEditorAction()}
- * for this text view. The default implementation will call your click
- * listener supplied to {@link #setOnEditorActionListener},
- * or generate an enter key down/up pair to invoke the action if not.
+ * for this text view. The default implementation will call your action
+ * listener supplied to {@link #setOnEditorActionListener}, or perform
+ * a standard operation for {@link EditorInfo#IME_ACTION_NEXT
+ * EditorInfo.IME_ACTION_NEXT} or {@link EditorInfo#IME_ACTION_DONE
+ * EditorInfo.IME_ACTION_DONE}.
+ *
+ * <p>For backwards compatibility, if no IME options have been set and the
+ * text view would not normally advance focus on enter, then
+ * the NEXT and DONE actions received here will be turned into an enter
+ * key down/up pair to go through the normal key handling.
*
* @param actionCode The code of the action being performed.
*
@@ -3052,6 +3061,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (imm != null) {
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
+ return;
}
}
@@ -3844,7 +3854,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (imm != null) {
if (imm.isActive(this)) {
boolean reported = false;
- if (ims.mContentChanged) {
+ if (ims.mContentChanged || ims.mSelectionModeChanged) {
// We are in extract mode and the content has changed
// in some way... just report complete new text to the
// input method.
@@ -4197,7 +4207,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
&& mInputContentType.enterDown) {
mInputContentType.enterDown = false;
if (mInputContentType.onEditorActionListener.onEditorAction(
- this, EditorInfo.IME_UNDEFINED, event)) {
+ this, EditorInfo.IME_NULL, event)) {
return true;
}
}
@@ -4272,17 +4282,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
outAttrs.actionId = mInputContentType.imeActionId;
outAttrs.extras = mInputContentType.extras;
} else {
- outAttrs.imeOptions = EditorInfo.IME_UNDEFINED;
+ outAttrs.imeOptions = EditorInfo.IME_NULL;
}
- if (outAttrs.imeOptions == EditorInfo.IME_UNDEFINED) {
+ if ((outAttrs.imeOptions&EditorInfo.IME_MASK_ACTION)
+ == EditorInfo.IME_ACTION_UNSPECIFIED) {
if (focusSearch(FOCUS_DOWN) != null) {
// An action has not been set, but the enter key will move to
// the next focus, so set the action to that.
- outAttrs.imeOptions = EditorInfo.IME_ACTION_NEXT;
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
} else {
// An action has not been set, and there is no focus to move
// to, so let's just supply a "done" action.
- outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE;
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_DONE;
}
if (!shouldAdvanceFocusOnEnter()) {
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION;
@@ -4307,51 +4318,64 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
public boolean extractText(ExtractedTextRequest request,
ExtractedText outText) {
- return extractTextInternal(request, -1, -1, -1, outText);
+ return extractTextInternal(request, EXTRACT_UNKNOWN, EXTRACT_UNKNOWN,
+ EXTRACT_UNKNOWN, outText);
}
+ static final int EXTRACT_NOTHING = -2;
+ static final int EXTRACT_UNKNOWN = -1;
+
boolean extractTextInternal(ExtractedTextRequest request,
int partialStartOffset, int partialEndOffset, int delta,
ExtractedText outText) {
final CharSequence content = mText;
if (content != null) {
- final int N = content.length();
- if (partialStartOffset < 0) {
- outText.partialStartOffset = outText.partialEndOffset = -1;
- partialStartOffset = 0;
- partialEndOffset = N;
- } else {
- // Adjust offsets to ensure we contain full spans.
- if (content instanceof Spanned) {
- Spanned spanned = (Spanned)content;
- Object[] spans = spanned.getSpans(partialStartOffset,
- partialEndOffset, ParcelableSpan.class);
- int i = spans.length;
- while (i > 0) {
- i--;
- int j = spanned.getSpanStart(spans[i]);
- if (j < partialStartOffset) partialStartOffset = j;
- j = spanned.getSpanEnd(spans[i]);
- if (j > partialEndOffset) partialEndOffset = j;
+ if (partialStartOffset != EXTRACT_NOTHING) {
+ final int N = content.length();
+ if (partialStartOffset < 0) {
+ outText.partialStartOffset = outText.partialEndOffset = -1;
+ partialStartOffset = 0;
+ partialEndOffset = N;
+ } else {
+ // Adjust offsets to ensure we contain full spans.
+ if (content instanceof Spanned) {
+ Spanned spanned = (Spanned)content;
+ Object[] spans = spanned.getSpans(partialStartOffset,
+ partialEndOffset, ParcelableSpan.class);
+ int i = spans.length;
+ while (i > 0) {
+ i--;
+ int j = spanned.getSpanStart(spans[i]);
+ if (j < partialStartOffset) partialStartOffset = j;
+ j = spanned.getSpanEnd(spans[i]);
+ if (j > partialEndOffset) partialEndOffset = j;
+ }
+ }
+ outText.partialStartOffset = partialStartOffset;
+ outText.partialEndOffset = partialEndOffset;
+ // Now use the delta to determine the actual amount of text
+ // we need.
+ partialEndOffset += delta;
+ if (partialEndOffset > N) {
+ partialEndOffset = N;
+ } else if (partialEndOffset < 0) {
+ partialEndOffset = 0;
}
}
- outText.partialStartOffset = partialStartOffset;
- outText.partialEndOffset = partialEndOffset;
- // Now use the delta to determine the actual amount of text
- // we need.
- partialEndOffset += delta;
- if (partialEndOffset > N) {
- partialEndOffset = N;
- } else if (partialEndOffset < 0) {
- partialEndOffset = 0;
+ if ((request.flags&InputConnection.GET_TEXT_WITH_STYLES) != 0) {
+ outText.text = content.subSequence(partialStartOffset,
+ partialEndOffset);
+ } else {
+ outText.text = TextUtils.substring(content, partialStartOffset,
+ partialEndOffset);
}
}
- if ((request.flags&InputConnection.GET_TEXT_WITH_STYLES) != 0) {
- outText.text = content.subSequence(partialStartOffset,
- partialEndOffset);
- } else {
- outText.text = TextUtils.substring(content, partialStartOffset,
- partialEndOffset);
+ outText.flags = 0;
+ if (MetaKeyKeyListener.getMetaState(mText, MetaKeyKeyListener.META_SELECTING) != 0) {
+ outText.flags |= ExtractedText.FLAG_SELECTING;
+ }
+ if (mSingleLine) {
+ outText.flags |= ExtractedText.FLAG_SINGLE_LINE;
}
outText.startOffset = 0;
outText.selectionStart = Selection.getSelectionStart(content);
@@ -4363,8 +4387,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
boolean reportExtractedText() {
final InputMethodState ims = mInputMethodState;
- if (ims != null && ims.mContentChanged) {
+ final boolean contentChanged = ims.mContentChanged;
+ if (ims != null && (contentChanged || ims.mSelectionModeChanged)) {
ims.mContentChanged = false;
+ ims.mSelectionModeChanged = false;
final ExtractedTextRequest req = mInputMethodState.mExtracting;
if (req != null) {
InputMethodManager imm = InputMethodManager.peekInstance();
@@ -4372,6 +4398,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (DEBUG_EXTRACT) Log.v(TAG, "Retrieving extracted start="
+ ims.mChangedStart + " end=" + ims.mChangedEnd
+ " delta=" + ims.mChangedDelta);
+ if (ims.mChangedStart < 0 && !contentChanged) {
+ ims.mChangedStart = EXTRACT_NOTHING;
+ }
if (extractTextInternal(req, ims.mChangedStart, ims.mChangedEnd,
ims.mChangedDelta, ims.mTmpExtracted)) {
if (DEBUG_EXTRACT) Log.v(TAG, "Reporting extracted start="
@@ -4408,19 +4437,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
public void setExtractedText(ExtractedText text) {
Editable content = getEditableText();
- if (content == null) {
- setText(text.text, TextView.BufferType.EDITABLE);
- } else if (text.partialStartOffset < 0) {
- removeParcelableSpans(content, 0, content.length());
- content.replace(0, content.length(), text.text);
- } else {
- final int N = content.length();
- int start = text.partialStartOffset;
- if (start > N) start = N;
- int end = text.partialEndOffset;
- if (end > N) end = N;
- removeParcelableSpans(content, start, end);
- content.replace(start, end, text.text);
+ if (text.text != null) {
+ if (content == null) {
+ setText(text.text, TextView.BufferType.EDITABLE);
+ } else if (text.partialStartOffset < 0) {
+ removeParcelableSpans(content, 0, content.length());
+ content.replace(0, content.length(), text.text);
+ } else {
+ final int N = content.length();
+ int start = text.partialStartOffset;
+ if (start > N) start = N;
+ int end = text.partialEndOffset;
+ if (end > N) end = N;
+ removeParcelableSpans(content, start, end);
+ content.replace(start, end, text.text);
+ }
}
// Now set the selection position... make sure it is in range, to
@@ -4436,6 +4467,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (end < 0) end = 0;
else if (end > N) end = N;
Selection.setSelection(sp, start, end);
+
+ // Finally, update the selection mode.
+ if ((text.flags&ExtractedText.FLAG_SELECTING) != 0) {
+ MetaKeyKeyListener.startSelecting(this, sp);
+ } else {
+ MetaKeyKeyListener.stopSelecting(this, sp);
+ }
}
/**
@@ -4473,8 +4511,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
ims.mChangedStart = 0;
ims.mChangedEnd = mText.length();
} else {
- ims.mChangedStart = -1;
- ims.mChangedEnd = -1;
+ ims.mChangedStart = EXTRACT_UNKNOWN;
+ ims.mChangedEnd = EXTRACT_UNKNOWN;
ims.mContentChanged = false;
}
onBeginBatchEdit();
@@ -4503,7 +4541,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
void finishBatchEdit(final InputMethodState ims) {
onEndBatchEdit();
- if (ims.mContentChanged) {
+ if (ims.mContentChanged || ims.mSelectionModeChanged) {
updateAfterEdit();
reportExtractedText();
} else if (ims.mCursorChanged) {
@@ -5888,6 +5926,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (MetaKeyKeyListener.isMetaTracker(buf, what)) {
mHighlightPathBogus = true;
+ if (ims != null && MetaKeyKeyListener.isSelectingMetaTracker(buf, what)) {
+ ims.mSelectionModeChanged = true;
+ }
if (Selection.getSelectionStart(buf) >= 0) {
if (ims == null || ims.mBatchEditNesting == 0) {
@@ -6026,7 +6067,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mSelectAllOnFocus) {
Selection.setSelection((Spannable) mText, 0, mText.length());
- mTouchFocusSelectedAll = true;
}
if (selMoved && selStart >= 0 && selEnd >= 0) {
@@ -6042,6 +6082,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Selection.setSelection((Spannable) mText, selStart, selEnd);
}
+ mTouchFocusSelected = true;
}
mFrozenWithFocus = false;
@@ -6149,7 +6190,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (action == MotionEvent.ACTION_DOWN) {
// Reset this state; it will be re-set if super.onTouchEvent
// causes focus to move to the view.
- mTouchFocusSelectedAll = false;
+ mTouchFocusSelected = false;
}
final boolean superResult = super.onTouchEvent(event);
@@ -6218,10 +6259,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* Returns true, only while processing a touch gesture, if the initial
* touch down event caused focus to move to the text view and as a result
- * it selected all of its text.
+ * its selection changed. Only valid while processing the touch gesture
+ * of interest.
*/
- public boolean didTouchFocusSelectAll() {
- return mTouchFocusSelectedAll;
+ public boolean didTouchFocusSelect() {
+ return mTouchFocusSelected;
}
@Override
@@ -6351,6 +6393,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return super.computeVerticalScrollRange();
}
+ @Override
+ protected int computeVerticalScrollExtent() {
+ return getHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom();
+ }
+
public enum BufferType {
NORMAL, SPANNABLE, EDITABLE,
}
@@ -6497,6 +6544,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* or null if there is no cursor or no word at the cursor.
*/
private String getWordForDictionary() {
+ /*
+ * Quick return if the input type is one where adding words
+ * to the dictionary doesn't make any sense.
+ */
+ int klass = mInputType & InputType.TYPE_MASK_CLASS;
+ if (klass == InputType.TYPE_CLASS_NUMBER ||
+ klass == InputType.TYPE_CLASS_PHONE ||
+ klass == InputType.TYPE_CLASS_DATETIME) {
+ return null;
+ }
+
+ int variation = mInputType & InputType.TYPE_MASK_VARIATION;
+ if (variation == InputType.TYPE_TEXT_VARIATION_URI ||
+ variation == InputType.TYPE_TEXT_VARIATION_PASSWORD ||
+ variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD ||
+ variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS ||
+ variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
+ return null;
+ }
+
int end = getSelectionEnd();
if (end < 0) {
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 1227afd..ec6f88b 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -46,8 +46,10 @@ import java.io.IOException;
* such as scaling and tinting.
*/
public class VideoView extends SurfaceView implements MediaPlayerControl {
+ private String TAG = "VideoView";
// settable by the client
private Uri mUri;
+ private int mDuration;
// All the stuff we need for playing and showing a video
private SurfaceHolder mSurfaceHolder = null;
@@ -184,6 +186,8 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mIsPrepared = false;
+ Log.v(TAG, "reset duration to -1 in openVideo");
+ mDuration = -1;
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
@@ -195,10 +199,10 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaPlayer.prepareAsync();
attachMediaController();
} catch (IOException ex) {
- Log.w("VideoView", "Unable to open content: " + mUri, ex);
+ Log.w(TAG, "Unable to open content: " + mUri, ex);
return;
} catch (IllegalArgumentException ex) {
- Log.w("VideoView", "Unable to open content: " + mUri, ex);
+ Log.w(TAG, "Unable to open content: " + mUri, ex);
return;
}
}
@@ -299,7 +303,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
private MediaPlayer.OnErrorListener mErrorListener =
new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int a, int b) {
- Log.d("VideoView", "Error: " + a + "," + b);
+ Log.d(TAG, "Error: " + a + "," + b);
if (mMediaController != null) {
mMediaController.hide();
}
@@ -497,9 +501,14 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
public int getDuration() {
if (mMediaPlayer != null && mIsPrepared) {
- return mMediaPlayer.getDuration();
+ if (mDuration > 0) {
+ return mDuration;
+ }
+ mDuration = mMediaPlayer.getDuration();
+ return mDuration;
}
- return -1;
+ mDuration = -1;
+ return mDuration;
}
public int getCurrentPosition() {
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index ec45e23..1ba2dce 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -16,14 +16,19 @@
package android.widget;
+import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
+import android.os.SystemClock;
import android.provider.Settings;
import android.view.Gravity;
import android.view.KeyEvent;
@@ -31,6 +36,7 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.WindowManager.LayoutParams;
@@ -46,7 +52,7 @@ import android.view.WindowManager.LayoutParams;
*
* @hide
*/
-public class ZoomButtonsController implements View.OnTouchListener {
+public class ZoomButtonsController implements View.OnTouchListener, View.OnKeyListener {
private static final String TAG = "ZoomButtonsController";
@@ -60,13 +66,13 @@ public class ZoomButtonsController implements View.OnTouchListener {
private WindowManager mWindowManager;
/**
- * The view that is being zoomed by this zoom ring.
+ * The view that is being zoomed by this zoom controller.
*/
private View mOwnerView;
/**
* The bounds of the owner view in global coordinates. This is recalculated
- * each time the zoom ring is shown.
+ * each time the zoom controller is shown.
*/
private Rect mOwnerViewBounds = new Rect();
@@ -89,11 +95,13 @@ public class ZoomButtonsController implements View.OnTouchListener {
*/
private int[] mTouchTargetLocationInWindow = new int[2];
/**
- * If the zoom ring is dismissed but the user is still in a touch
+ * If the zoom controller is dismissed but the user is still in a touch
* interaction, we set this to true. This will ignore all touch events until
* up/cancel, and then set the owner's touch listener to null.
*/
private boolean mReleaseTouchListenerOnUp;
+
+ private boolean mIsSecondTapDown;
private boolean mIsVisible;
@@ -122,10 +130,16 @@ public class ZoomButtonsController implements View.OnTouchListener {
}
};
+ /**
+ * The setting name that tracks whether we've shown the zoom tutorial.
+ */
+ private static final String SETTING_NAME_SHOWN_TUTORIAL = "shown_zoom_tutorial";
+ private static Dialog sTutorialDialog;
+
/** When configuration changes, this is called after the UI thread is idle. */
private static final int MSG_POST_CONFIGURATION_CHANGED = 2;
- /** Used to delay the zoom ring dismissal. */
- private static final int MSG_DISMISS_ZOOM_RING = 3;
+ /** Used to delay the zoom controller dismissal. */
+ private static final int MSG_DISMISS_ZOOM_CONTROLS = 3;
/**
* If setVisible(true) is called and the owner view's window token is null,
* we delay the setVisible(true) call until it is not null.
@@ -140,7 +154,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
onPostConfigurationChanged();
break;
- case MSG_DISMISS_ZOOM_RING:
+ case MSG_DISMISS_ZOOM_CONTROLS:
setVisible(false);
break;
@@ -148,7 +162,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
if (mOwnerView.getWindowToken() == null) {
// Doh, it is still null, throw an exception
throw new IllegalArgumentException(
- "Cannot make the zoom ring visible if the owner view is " +
+ "Cannot make the zoom controller visible if the owner view is " +
"not attached to a window.");
}
setVisible(true);
@@ -165,11 +179,24 @@ public class ZoomButtonsController implements View.OnTouchListener {
mContainer = createContainer();
}
-
+
+ public void setZoomInEnabled(boolean enabled) {
+ mControls.setIsZoomInEnabled(enabled);
+ }
+
+ public void setZoomOutEnabled(boolean enabled) {
+ mControls.setIsZoomOutEnabled(enabled);
+ }
+
+ public void setZoomSpeed(long speed) {
+ mControls.setZoomSpeed(speed);
+ }
+
private FrameLayout createContainer() {
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.BOTTOM | Gravity.CENTER;
lp.flags = LayoutParams.FLAG_NOT_TOUCHABLE |
+ LayoutParams.FLAG_NOT_FOCUSABLE |
LayoutParams.FLAG_LAYOUT_NO_LIMITS;
lp.height = LayoutParams.WRAP_CONTENT;
lp.width = LayoutParams.FILL_PARENT;
@@ -182,6 +209,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
FrameLayout container = new FrameLayout(mContext);
container.setLayoutParams(lp);
container.setMeasureAllChildren(true);
+ container.setOnKeyListener(this);
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -326,13 +354,13 @@ public class ZoomButtonsController implements View.OnTouchListener {
return mContainer;
}
- public int getZoomRingId() {
+ public int getZoomControlsId() {
return mControls.getId();
}
private void dismissControlsDelayed(int delay) {
- mHandler.removeMessages(MSG_DISMISS_ZOOM_RING);
- mHandler.sendEmptyMessageDelayed(MSG_DISMISS_ZOOM_RING, delay);
+ mHandler.removeMessages(MSG_DISMISS_ZOOM_CONTROLS);
+ mHandler.sendEmptyMessageDelayed(MSG_DISMISS_ZOOM_CONTROLS, delay);
}
/**
@@ -351,8 +379,21 @@ public class ZoomButtonsController implements View.OnTouchListener {
int x = (int) event.getX();
int y = (int) event.getY();
+ /*
+ * This class will consume all events in the second tap (down,
+ * move(s), up). But, the owner already got the second tap's down,
+ * so cancel that. Do this before setVisible, since that call
+ * will set us as a touch listener.
+ */
+ MotionEvent cancelEvent = MotionEvent.obtain(event.getDownTime(),
+ SystemClock.elapsedRealtime(),
+ MotionEvent.ACTION_CANCEL, 0, 0, 0);
+ mOwnerView.dispatchTouchEvent(cancelEvent);
+ cancelEvent.recycle();
+
setVisible(true);
centerPoint(x, y);
+ mIsSecondTapDown = true;
}
return true;
@@ -373,11 +414,23 @@ public class ZoomButtonsController implements View.OnTouchListener {
}
}
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
+ return false;
+ }
+
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
+ // Consume all events during the second-tap interaction (down, move, up/cancel)
+ boolean consumeEvent = mIsSecondTapDown;
+ if ((action == MotionEvent.ACTION_UP) || (action == MotionEvent.ACTION_CANCEL)) {
+ // The second tap can no longer be down
+ mIsSecondTapDown = false;
+ }
+
if (mReleaseTouchListenerOnUp) {
- // The ring was dismissed but we need to throw away all events until the up
+ // The controls were 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);
@@ -417,10 +470,10 @@ public class ZoomButtonsController implements View.OnTouchListener {
mOwnerViewBounds.top - targetViewRawY);
boolean retValue = targetView.dispatchTouchEvent(containerEvent);
containerEvent.recycle();
- return retValue;
+ return retValue || consumeEvent;
} else {
- return false;
+ return consumeEvent;
}
}
@@ -465,10 +518,102 @@ public class ZoomButtonsController implements View.OnTouchListener {
refreshPositioningVariables();
}
+ /*
+ * This is static so Activities can call this instead of the Views
+ * (Activities usually do not have a reference to the ZoomButtonsController
+ * instance.)
+ */
+ /**
+ * Shows a "tutorial" (some text) to the user teaching her the new zoom
+ * invocation method. Must call from the main thread.
+ * <p>
+ * It checks the global system setting to ensure this has not been seen
+ * before. Furthermore, if the application does not have privilege to write
+ * to the system settings, it will store this bit locally in a shared
+ * preference.
+ *
+ * @hide This should only be used by our main apps--browser, maps, and
+ * gallery
+ */
+ public static void showZoomTutorialOnce(Context context) {
+ ContentResolver cr = context.getContentResolver();
+ if (Settings.System.getInt(cr, SETTING_NAME_SHOWN_TUTORIAL, 0) == 1) {
+ return;
+ }
+
+ SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE);
+ if (sp.getInt(SETTING_NAME_SHOWN_TUTORIAL, 0) == 1) {
+ return;
+ }
+
+ if (sTutorialDialog != null && sTutorialDialog.isShowing()) {
+ sTutorialDialog.dismiss();
+ }
+
+ LayoutInflater layoutInflater =
+ (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ TextView textView = (TextView) layoutInflater.inflate(
+ com.android.internal.R.layout.alert_dialog_simple_text, null)
+ .findViewById(android.R.id.text1);
+ textView.setText(com.android.internal.R.string.tutorial_double_tap_to_zoom_message_short);
+
+ sTutorialDialog = new AlertDialog.Builder(context)
+ .setView(textView)
+ .setIcon(0)
+ .create();
+
+ Window window = sTutorialDialog.getWindow();
+ window.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+ window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND |
+ WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+ window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+
+ sTutorialDialog.show();
+ }
+
+ /** @hide Should only be used by Android platform apps */
+ public static void finishZoomTutorial(Context context, boolean userNotified) {
+ if (sTutorialDialog == null) return;
+
+ sTutorialDialog.dismiss();
+ sTutorialDialog = null;
+
+ // Record that they have seen the tutorial
+ if (userNotified) {
+ try {
+ Settings.System.putInt(context.getContentResolver(), SETTING_NAME_SHOWN_TUTORIAL,
+ 1);
+ } catch (SecurityException e) {
+ /*
+ * The app does not have permission to clear this global flag, make
+ * sure the user does not see the message when he comes back to this
+ * same app at least.
+ */
+ SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE);
+ sp.edit().putInt(SETTING_NAME_SHOWN_TUTORIAL, 1).commit();
+ }
+ }
+ }
+
+ /** @hide Should only be used by Android platform apps */
+ public void finishZoomTutorial() {
+ finishZoomTutorial(mContext, true);
+ }
+
+ // Temporary methods for different zoom types
+ static int getZoomType(Context context) {
+ return Settings.System.getInt(context.getContentResolver(), "zoom", 1);
+ }
+
+ public static boolean useOldZoom(Context context) {
+ return getZoomType(context) == 0;
+ }
+
public static boolean useThisZoom(Context context) {
- return ZoomRingController.getZoomType(context) == 2;
+ return getZoomType(context) == 2;
}
-
+
public interface OnZoomListener {
void onCenter(int x, int y);
void onVisibilityChanged(boolean visible);
diff --git a/core/java/android/widget/ZoomControls.java b/core/java/android/widget/ZoomControls.java
index fdc05b6..e978db8 100644
--- a/core/java/android/widget/ZoomControls.java
+++ b/core/java/android/widget/ZoomControls.java
@@ -81,7 +81,7 @@ public class ZoomControls extends LinearLayout {
}
public void show() {
- if (ZoomRingController.useOldZoom(mContext)) {
+ if (ZoomButtonsController.useOldZoom(mContext)) {
fade(View.VISIBLE, 0.0f, 1.0f);
}
}
diff --git a/core/java/android/widget/ZoomRing.java b/core/java/android/widget/ZoomRing.java
deleted file mode 100644
index 83a1225..0000000
--- a/core/java/android/widget/ZoomRing.java
+++ /dev/null
@@ -1,1274 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget;
-
-import com.android.internal.R;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.RotateDrawable;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.HapticFeedbackConstants;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-
-/**
- * A view that has a draggable thumb on a circle.
- *
- * @hide
- */
-public class ZoomRing extends View {
- private static final String TAG = "ZoomRing";
-
- // TODO: Temporary until the trail is done
- private static final boolean DRAW_TRAIL = false;
-
- /**
- * To avoid floating point calculations and int round-offs, we multiply
- * radians by this value.
- */
- public static final int RADIAN_INT_MULTIPLIER = 10000;
- /** The allowable margin of error when comparing two angles. */
- public static final int RADIAN_INT_ERROR = 100;
- public static final int PI_INT_MULTIPLIED = (int) (Math.PI * RADIAN_INT_MULTIPLIER);
- public static final int TWO_PI_INT_MULTIPLIED = PI_INT_MULTIPLIED * 2;
- private static final int HALF_PI_INT_MULTIPLIED = PI_INT_MULTIPLIED / 2;
-
- private static final int DOUBLE_TAP_DISMISS_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();
- private final int mTouchSlop;
-
- /** The slop when the user is grabbing the thumb. */
- private static final int THUMB_GRAB_SLOP = PI_INT_MULTIPLIED / 8;
- /** The slop until a user starts dragging the thumb. */
- private static final int THUMB_DRAG_SLOP = PI_INT_MULTIPLIED / 12;
-
- /** The distance (in px) from the center of the ring to the center of the thumb. */
- private int mThumbDistance;
-
- /** The angle on a unit circle that is considered to be the zoom ring's 0 degree. */
- private int mZeroAngle = HALF_PI_INT_MULTIPLIED * 3;
-
- /**
- * The maximum delta angle that the thumb can move. The primary use is to
- * ensure that when a user taps on the ring, the movement to reach that
- * target angle is not ambiguous (for example, if the thumb is at 0 and he
- * taps 180, should the thumb go clockwise or counterclockwise?
- * <p>
- * Includes error because we compare this to the result of
- * getDelta(getClosestTickeAngle(..), oldAngle) which ends up having some
- * rounding error.
- */
- private static final int MAX_ABS_JUMP_DELTA_ANGLE = (2 * PI_INT_MULTIPLIED / 3) +
- RADIAN_INT_ERROR;
-
- /** The cached X of the zoom ring's center (in zoom ring coordinates). */
- private int mCenterX;
- /** The cached Y of the zoom ring's center (in zoom ring coordinates). */
- private int mCenterY;
-
- /** The angle of the thumb (in int radians) */
- private int mThumbAngle;
- /** The cached width/2 of the zoom ring. */
- private int mThumbHalfWidth;
- /** The cached height/2 of the zoom ring. */
- private int mThumbHalfHeight;
-
- /**
- * The bound for the thumb's movement when it is being dragged clockwise.
- * Can be Integer.MIN_VALUE if there is no bound in this direction.
- */
- private int mThumbCwBound = Integer.MIN_VALUE;
- /**
- * The bound for the thumb's movement when it is being dragged
- * counterclockwise. Can be Integer.MIN_VALUE if there is no bound in this
- * direction.
- */
- private int mThumbCcwBound = Integer.MIN_VALUE;
-
- /**
- * Whether to enforce the maximum absolute jump delta. See
- * {@link #MAX_ABS_JUMP_DELTA_ANGLE}.
- */
- private boolean mEnforceMaxAbsJump = true;
-
- /** The inner radius of the track. */
- private int mTrackInnerRadius;
- /** Cached square of the inner radius of the track. */
- private int mTrackInnerRadiusSquared;
- /** The outer radius of the track. */
- private int mTrackOuterRadius;
- /** Cached square of the outer radius of the track. */
- private int mTrackOuterRadiusSquared;
-
- /** The raw X of where the widget previously was located. */
- private int mPreviousWidgetDragX;
- /** The raw Y of where the widget previously was located. */
- private int mPreviousWidgetDragY;
-
- /** Whether the thumb should be visible. */
- private boolean mThumbVisible = true;
-
- /** The drawable for the thumb. */
- private Drawable mThumbDrawable;
-
- /** Shown beneath the thumb if we can still zoom in. */
- private Drawable mZoomInArrowDrawable;
- /** Shown beneath the thumb if we can still zoom out. */
- private Drawable mZoomOutArrowDrawable;
-
- /** @see #mThumbArrowsToDraw */
- private static final int THUMB_ARROW_PLUS = 1 << 0;
- /** @see #mThumbArrowsToDraw */
- private static final int THUMB_ARROW_MINUS = 1 << 1;
- /** Bitwise-OR of {@link #THUMB_ARROW_MINUS} and {@link #THUMB_ARROW_PLUS} */
- private int mThumbArrowsToDraw;
-
- /** The duration for the thumb arrows fading out */
- private static final int THUMB_ARROWS_FADE_DURATION = 300;
- /** The time when the fade out started. */
- private long mThumbArrowsFadeStartTime;
- /** The current alpha for the thumb arrows. */
- private int mThumbArrowsAlpha = 255;
-
- /** The distance from the center to the zoom arrow hints (usually plus and minus). */
- private int mZoomArrowHintDistance;
- /** The offset angle from the thumb angle to draw the zoom arrow hints. */
- private int mZoomArrowHintOffsetAngle = TWO_PI_INT_MULTIPLIED / 11;
- /** Drawn (without rotation) on top of the arrow. */
- private Drawable mZoomInArrowHintDrawable;
- /** Drawn (without rotation) on top of the arrow. */
- private Drawable mZoomOutArrowHintDrawable;
-
- /** Zoom ring is just chillin' */
- private static final int MODE_IDLE = 0;
- /**
- * User has his finger down somewhere on the ring (besides the thumb) and we
- * are waiting for him to move the slop amount before considering him in the
- * drag thumb state.
- */
- private static final int MODE_WAITING_FOR_DRAG_THUMB_AFTER_JUMP = 5;
- /** User is dragging the thumb. */
- private static final int MODE_DRAG_THUMB = 1;
- /**
- * User has his finger down, but we are waiting for him to pass the touch
- * slop before going into the #MODE_MOVE_ZOOM_RING. This is a good time to
- * show the movable hint.
- */
- private static final int MODE_WAITING_FOR_MOVE_ZOOM_RING = 4;
- /** User is moving the zoom ring. */
- private static final int MODE_MOVE_ZOOM_RING = 2;
- /** User is dragging the thumb via tap-drag. */
- private static final int MODE_TAP_DRAG = 3;
- /** Ignore the touch interaction until the user touches the thumb again. */
- private static final int MODE_IGNORE_UNTIL_TOUCHES_THUMB = 6;
- /** The current mode of interaction. */
- private int mMode;
- /** Records the last mode the user was in. */
- private int mPreviousMode;
-
- /** The previous time of the up-touch on the center. */
- private long mPreviousCenterUpTime;
- /** The previous X of down-touch. */
- private int mPreviousDownX;
- /** The previous Y of down-touch. */
- private int mPreviousDownY;
-
- /** The angle where the user first grabbed the thumb. */
- private int mInitialGrabThumbAngle;
-
- /** The callback. */
- private OnZoomRingCallback mCallback;
- /** The tick angle that we previously called back with. */
- private int mPreviousCallbackTickAngle;
- /** The delta angle between ticks. A tick is a callback point. */
- private int mTickDelta = Integer.MAX_VALUE;
- /** If the user drags to within __% of a tick, snap to that tick. */
- private int mFuzzyTickDelta = Integer.MAX_VALUE;
-
- /** The angle where the thumb is officially starting to be dragged. */
- private int mThumbDragStartAngle;
-
- /** The drawable for the zoom trail. */
- private Drawable mTrail;
- /** The accumulated angle for the trail. */
- private double mAcculumalatedTrailAngle;
-
- /** The animation-step tracker for scrolling the thumb to a particular position. */
- private Scroller mThumbScroller;
-
- /** Whether to ever vibrate when passing a tick. */
- private boolean mVibration = true;
-
- /** The drawable used to hint that this can pan its owner. */
- private Drawable mPanningArrowsDrawable;
-
- private static final int MSG_THUMB_SCROLLER_STEP = 1;
- private static final int MSG_THUMB_ARROWS_FADE_STEP = 2;
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_THUMB_SCROLLER_STEP:
- onThumbScrollerStep();
- break;
-
- case MSG_THUMB_ARROWS_FADE_STEP:
- onThumbArrowsFadeStep();
- break;
- }
- }
- };
-
- public ZoomRing(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
- mTouchSlop = viewConfiguration.getScaledTouchSlop();
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ZoomRing, defStyle, 0);
- mThumbDistance = (int) a.getDimension(R.styleable.ZoomRing_thumbDistance, 0);
- setTrackRadii(
- (int) a.getDimension(R.styleable.ZoomRing_trackInnerRadius, 0),
- (int) a.getDimension(R.styleable.ZoomRing_trackOuterRadius, Integer.MAX_VALUE));
- mThumbDrawable = a.getDrawable(R.styleable.ZoomRing_thumbDrawable);
- mZoomInArrowDrawable = a.getDrawable(R.styleable.ZoomRing_zoomInArrowDrawable);
- mZoomOutArrowDrawable = a.getDrawable(R.styleable.ZoomRing_zoomOutArrowDrawable);
- mZoomInArrowHintDrawable = a.getDrawable(R.styleable.ZoomRing_zoomInArrowHintDrawable);
- mZoomOutArrowHintDrawable = a.getDrawable(R.styleable.ZoomRing_zoomOutArrowHintDrawable);
- mZoomArrowHintDistance =
- (int) a.getDimension(R.styleable.ZoomRing_zoomArrowHintDistance, 0);
- mZoomArrowHintOffsetAngle =
- (int) (a.getInteger(R.styleable.ZoomRing_zoomArrowHintOffsetAngle, 0)
- * TWO_PI_INT_MULTIPLIED / 360);
- mPanningArrowsDrawable = a.getDrawable(R.styleable.ZoomRing_panningArrowsDrawable);
- a.recycle();
-
- Resources res = context.getResources();
- if (DRAW_TRAIL) {
- // TODO get drawables from style instead
- mTrail = res.getDrawable(R.drawable.zoom_ring_trail).mutate();
- }
-
- mThumbHalfHeight = mThumbDrawable.getIntrinsicHeight() / 2;
- mThumbHalfWidth = mThumbDrawable.getIntrinsicWidth() / 2;
-
- setTickDelta(PI_INT_MULTIPLIED / 6);
- }
-
- public ZoomRing(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.zoomRingStyle);
- }
-
- public ZoomRing(Context context) {
- this(context, null);
- }
-
- public void setTrackDrawable(Drawable drawable) {
- setBackgroundDrawable(drawable);
- }
-
- public void setCallback(OnZoomRingCallback callback) {
- mCallback = callback;
- }
-
- /**
- * Sets the distance between ticks. This will be used as a callback threshold.
- *
- * @param angle The angle between ticks.
- */
- public void setTickDelta(int angle) {
- mTickDelta = angle;
- mFuzzyTickDelta = (int) (angle * 0.65f);
- }
-
- public void setVibration(boolean vibration) {
- mVibration = vibration;
- }
-
- public void setThumbVisible(boolean thumbVisible) {
- if (mThumbVisible != thumbVisible) {
- mThumbVisible = thumbVisible;
- invalidate();
- }
- }
-
- public Drawable getPanningArrowsDrawable() {
- return mPanningArrowsDrawable;
- }
-
- public void setTrackRadii(int innerRadius, int outerRadius) {
- mTrackInnerRadius = innerRadius;
- mTrackOuterRadius = outerRadius;
-
- mTrackInnerRadiusSquared = innerRadius * innerRadius;
- if (mTrackInnerRadiusSquared < innerRadius) {
- // Prevent overflow
- mTrackInnerRadiusSquared = Integer.MAX_VALUE;
- }
-
- mTrackOuterRadiusSquared = outerRadius * outerRadius;
- if (mTrackOuterRadiusSquared < outerRadius) {
- // Prevent overflow
- mTrackOuterRadiusSquared = Integer.MAX_VALUE;
- }
- }
-
- public int getTrackInnerRadius() {
- return mTrackInnerRadius;
- }
-
- public int getTrackOuterRadius() {
- return mTrackOuterRadius;
- }
-
- public void setThumbClockwiseBound(int angle) {
- if (angle < 0) {
- mThumbCwBound = Integer.MIN_VALUE;
- } else {
- mThumbCwBound = getClosestTickAngle(angle);
- }
- updateEnforceMaxAbsJump();
- }
-
- public void setThumbCounterclockwiseBound(int angle) {
- if (angle < 0) {
- mThumbCcwBound = Integer.MIN_VALUE;
- } else {
- mThumbCcwBound = getClosestTickAngle(angle);
- }
- updateEnforceMaxAbsJump();
- }
-
- private void updateEnforceMaxAbsJump() {
- // If there are bounds in both direction, there is no reason to restrict
- // the amount that a user can absolute jump to
- mEnforceMaxAbsJump =
- mThumbCcwBound == Integer.MIN_VALUE || mThumbCwBound == Integer.MIN_VALUE;
- }
-
- public int getThumbAngle() {
- return mThumbAngle;
- }
-
- public void setThumbAngle(int angle) {
- angle = getValidAngle(angle);
- mPreviousCallbackTickAngle = getClosestTickAngle(angle);
- setThumbAngleAuto(angle, false, false);
- }
-
- /**
- * Sets the thumb angle. If already animating, will continue the animation,
- * otherwise it will do a direct jump.
- *
- * @param angle
- * @param useDirection Whether to use the ccw parameter
- * @param ccw Whether going counterclockwise (only used if useDirection is true)
- */
- private void setThumbAngleAuto(int angle, boolean useDirection, boolean ccw) {
- if (mThumbScroller == null
- || mThumbScroller.isFinished()
- || Math.abs(getDelta(angle, getThumbScrollerAngle())) < THUMB_GRAB_SLOP) {
- setThumbAngleInt(angle);
- } else {
- if (useDirection) {
- setThumbAngleAnimated(angle, 0, ccw);
- } else {
- setThumbAngleAnimated(angle, 0);
- }
- }
- }
-
- private void setThumbAngleInt(int angle) {
- mThumbAngle = angle;
- int unoffsetAngle = angle + mZeroAngle;
- int thumbCenterX = (int) (Math.cos(1f * unoffsetAngle / RADIAN_INT_MULTIPLIER) *
- mThumbDistance) + mCenterX;
- int thumbCenterY = (int) (Math.sin(1f * unoffsetAngle / RADIAN_INT_MULTIPLIER) *
- mThumbDistance) * -1 + mCenterY;
-
- mThumbDrawable.setBounds(thumbCenterX - mThumbHalfWidth,
- thumbCenterY - mThumbHalfHeight,
- thumbCenterX + mThumbHalfWidth,
- thumbCenterY + mThumbHalfHeight);
-
- if (mThumbArrowsToDraw > 0) {
- setThumbArrowsAngle(angle);
- }
-
- if (DRAW_TRAIL) {
- double degrees;
- degrees = Math.min(359.0, Math.abs(mAcculumalatedTrailAngle));
- int level = (int) (10000.0 * degrees / 360.0);
-
- mTrail.setLevel((int) (10000.0 *
- (-Math.toDegrees(angle / (double) RADIAN_INT_MULTIPLIER) -
- degrees + 90) / 360.0));
- ((RotateDrawable) mTrail).getDrawable().setLevel(level);
- }
-
- invalidate();
- }
-
- /**
- *
- * @param angle
- * @param duration The animation duration, or 0 for the default duration.
- */
- public void setThumbAngleAnimated(int angle, int duration) {
- // The angle when going from the current angle to the new angle
- int deltaAngle = getDelta(mThumbAngle, angle);
- setThumbAngleAnimated(angle, duration, deltaAngle > 0);
- }
-
- public void setThumbAngleAnimated(int angle, int duration, boolean counterClockwise) {
- if (mThumbScroller == null) {
- mThumbScroller = new Scroller(mContext);
- }
-
- int startAngle = mThumbAngle;
- int endAngle = getValidAngle(angle);
- int deltaAngle = getDelta(startAngle, endAngle, counterClockwise);
- if (startAngle + deltaAngle < 0) {
- // Keep our angles positive
- startAngle += TWO_PI_INT_MULTIPLIED;
- }
-
- if (!mThumbScroller.isFinished()) {
- duration = mThumbScroller.getDuration() - mThumbScroller.timePassed();
- } else if (duration == 0) {
- duration = getAnimationDuration(deltaAngle);
- }
- mThumbScroller.startScroll(startAngle, 0, deltaAngle, 0, duration);
- onThumbScrollerStep();
- }
-
- private int getAnimationDuration(int deltaAngle) {
- if (deltaAngle < 0) deltaAngle *= -1;
- return 300 + deltaAngle * 300 / RADIAN_INT_MULTIPLIER;
- }
-
- private void onThumbScrollerStep() {
- if (!mThumbScroller.computeScrollOffset()) return;
- setThumbAngleInt(getThumbScrollerAngle());
- mHandler.sendEmptyMessage(MSG_THUMB_SCROLLER_STEP);
- }
-
- private int getThumbScrollerAngle() {
- return mThumbScroller.getCurrX() % TWO_PI_INT_MULTIPLIED;
- }
-
- public void resetThumbAngle() {
- mPreviousCallbackTickAngle = 0;
- setThumbAngleInt(0);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec),
- resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec));
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right,
- int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- // Cache the center point
- mCenterX = (right - left) / 2;
- mCenterY = (bottom - top) / 2;
-
- // Done here since we now have center, which is needed to calculate some
- // aux info for thumb angle
- if (mThumbAngle == Integer.MIN_VALUE) {
- resetThumbAngle();
- }
-
- if (DRAW_TRAIL) {
- mTrail.setBounds(0, 0, right - left, bottom - top);
- }
-
- // These drawables are the same size as the track
- mZoomInArrowDrawable.setBounds(0, 0, right - left, bottom - top);
- mZoomOutArrowDrawable.setBounds(0, 0, right - left, bottom - top);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- return handleTouch(event.getAction(), event.getEventTime(),
- (int) event.getX(), (int) event.getY(), (int) event.getRawX(),
- (int) event.getRawY());
- }
-
- private void resetToIdle() {
- setMode(MODE_IDLE);
- mPreviousWidgetDragX = mPreviousWidgetDragY = Integer.MIN_VALUE;
- mAcculumalatedTrailAngle = 0.0;
- }
-
- public void setTapDragMode(boolean tapDragMode, int x, int y) {
- resetToIdle();
- if (tapDragMode) {
- setMode(MODE_TAP_DRAG);
- mCallback.onUserInteractionStarted();
- onThumbDragStarted(getAngle(x - mCenterX, y - mCenterY));
- } else {
- onTouchUp(SystemClock.elapsedRealtime(), true);
- }
- }
-
- public boolean handleTouch(int action, long time, int x, int y, int rawX, int rawY) {
- // local{X,Y} will be where the center of the widget is (0,0)
- int localX = x - mCenterX;
- int localY = y - mCenterY;
-
- /*
- * If we are not drawing the thumb, there is no way for the user to be
- * touching the thumb. Also, if this is the case, assume they are not
- * touching the ring (so the user cannot absolute set the thumb, and
- * there will be a larger touch region for going into the move-ring
- * mode).
- */
- boolean isTouchingThumb = mThumbVisible;
- boolean isTouchingRing = mThumbVisible;
-
- int touchAngle = getAngle(localX, localY);
-
- int radiusSquared = localX * localX + localY * localY;
- if (radiusSquared < mTrackInnerRadiusSquared ||
- radiusSquared > mTrackOuterRadiusSquared) {
- // Out-of-bounds
- isTouchingThumb = false;
- isTouchingRing = false;
- }
-
- if (isTouchingThumb) {
- int deltaThumbAndTouch = getDelta(mThumbAngle, touchAngle);
- int absoluteDeltaThumbAndTouch = deltaThumbAndTouch >= 0 ?
- deltaThumbAndTouch : -deltaThumbAndTouch;
- if (absoluteDeltaThumbAndTouch > THUMB_GRAB_SLOP) {
- // Didn't grab close enough to the thumb
- isTouchingThumb = false;
- }
- }
-
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- if (!isTouchingRing &&
- (time - mPreviousCenterUpTime <= DOUBLE_TAP_DISMISS_TIMEOUT)) {
- // Make sure the double-tap is in the center of the widget (and not on the ring)
- mCallback.onZoomRingDismissed();
- onTouchUp(time, isTouchingRing);
-
- // Dismissing, so halt here
- return true;
- }
-
- resetToIdle();
- mCallback.onUserInteractionStarted();
- mPreviousDownX = x;
- mPreviousDownY = y;
- // Fall through to code below switch (since the down is used for
- // jumping to the touched tick)
- break;
-
- case MotionEvent.ACTION_MOVE:
- // Fall through to code below switch
- break;
-
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- onTouchUp(time, isTouchingRing);
- return true;
-
- default:
- return false;
- }
-
- if (mMode == MODE_IDLE) {
- if (isTouchingThumb) {
- // They grabbed the thumb
- setMode(MODE_DRAG_THUMB);
- onThumbDragStarted(touchAngle);
-
- } else if (isTouchingRing) {
- // They tapped somewhere else on the ring
- int tickAngle = getClosestTickAngle(touchAngle);
- int deltaThumbAndTick = getDelta(mThumbAngle, tickAngle);
- int boundAngle = getBoundIfExceeds(mThumbAngle, deltaThumbAndTick);
-
- if (mEnforceMaxAbsJump) {
- // Enforcing the max jump
- if (deltaThumbAndTick > MAX_ABS_JUMP_DELTA_ANGLE ||
- deltaThumbAndTick < -MAX_ABS_JUMP_DELTA_ANGLE) {
- // Trying to jump too far, ignore this touch interaction
- setMode(MODE_IGNORE_UNTIL_TOUCHES_THUMB);
- return true;
- }
-
- if (boundAngle != Integer.MIN_VALUE) {
- // Cap the user's jump to the bound
- tickAngle = boundAngle;
- }
- } else {
- // Not enforcing the max jump, but we have to make sure
- // we're getting to the tapped angle by going through the
- // in-bounds region
- if (boundAngle != Integer.MIN_VALUE) {
- // Going this direction hits a bound, let's go the opposite direction
- boolean oldDirectionIsCcw = deltaThumbAndTick > 0;
- deltaThumbAndTick = getDelta(mThumbAngle, tickAngle, !oldDirectionIsCcw);
- boundAngle = getBoundIfExceeds(mThumbAngle, deltaThumbAndTick);
- if (boundAngle != Integer.MIN_VALUE) {
- // Cannot get to the tapped location because it is out-of-bounds
- setMode(MODE_IGNORE_UNTIL_TOUCHES_THUMB);
- return true;
- }
- }
- }
-
- setMode(MODE_WAITING_FOR_DRAG_THUMB_AFTER_JUMP);
- mInitialGrabThumbAngle = touchAngle;
- boolean ccw = deltaThumbAndTick > 0;
- setThumbAngleAnimated(tickAngle, 0, ccw);
-
- /*
- * Our thumb scrolling animation takes us from mThumbAngle to
- * tickAngle, so manifest that as the user dragging the thumb
- * there.
- */
- onThumbDragStarted(mThumbAngle);
- // We know which direction we want to go
- onThumbDragged(tickAngle, true, ccw);
-
- } else {
- // They tapped somewhere else on the widget
- setMode(MODE_WAITING_FOR_MOVE_ZOOM_RING);
- mCallback.onZoomRingSetMovableHintVisible(true);
- }
-
- } else if (mMode == MODE_WAITING_FOR_DRAG_THUMB_AFTER_JUMP) {
- int deltaDownAngle = getDelta(mInitialGrabThumbAngle, touchAngle);
- if ((deltaDownAngle < -THUMB_DRAG_SLOP || deltaDownAngle > THUMB_DRAG_SLOP) &&
- isDeltaInBounds(mInitialGrabThumbAngle, deltaDownAngle)) {
- setMode(MODE_DRAG_THUMB);
-
- // No need to call onThumbDragStarted, since that was done when they tapped-to-jump
- }
-
- } else if (mMode == MODE_WAITING_FOR_MOVE_ZOOM_RING) {
- if (Math.abs(x - mPreviousDownX) > mTouchSlop ||
- Math.abs(y - mPreviousDownY) > mTouchSlop) {
- /* Make sure the user has moved the slop amount before going into that mode. */
- setMode(MODE_MOVE_ZOOM_RING);
- mCallback.onZoomRingMovingStarted();
- // Move the zoom ring so it is under the finger where the user first touched
- mCallback.onZoomRingMoved(x - mPreviousDownX, y - mPreviousDownY, rawX, rawY);
- }
- } else if (mMode == MODE_IGNORE_UNTIL_TOUCHES_THUMB) {
- if (isTouchingThumb) {
- // The user is back on the thumb, let's go back to the previous mode
- setMode(mPreviousMode);
- }
- }
-
- // Purposefully not an "else if"
- if (mMode == MODE_DRAG_THUMB || mMode == MODE_TAP_DRAG) {
- if (isTouchingRing) {
- onThumbDragged(touchAngle, false, false);
- }
- } else if (mMode == MODE_MOVE_ZOOM_RING) {
- onZoomRingMoved(rawX, rawY);
- }
-
- return true;
- }
-
- private void onTouchUp(long time, boolean isTouchingRing) {
- int mode = mMode;
- if (mode == MODE_IGNORE_UNTIL_TOUCHES_THUMB) {
- // For cleaning up, pretend like the user was still in the previous mode
- mode = mPreviousMode;
- }
-
- if (mode == MODE_MOVE_ZOOM_RING || mode == MODE_WAITING_FOR_MOVE_ZOOM_RING) {
- mCallback.onZoomRingSetMovableHintVisible(false);
- if (mode == MODE_MOVE_ZOOM_RING) {
- mCallback.onZoomRingMovingStopped();
- }
- } else if (mode == MODE_DRAG_THUMB || mode == MODE_TAP_DRAG ||
- mode == MODE_WAITING_FOR_DRAG_THUMB_AFTER_JUMP) {
- onThumbDragStopped();
-
- if (mode == MODE_DRAG_THUMB || mode == MODE_TAP_DRAG) {
- // Animate back to a tick
- setThumbAngleAnimated(mPreviousCallbackTickAngle, 0);
- }
- }
- mCallback.onUserInteractionStopped();
-
- if (!isTouchingRing) {
- mPreviousCenterUpTime = time;
- }
- }
-
- private void setMode(int mode) {
- if (mode != mMode) {
- mPreviousMode = mMode;
- mMode = mode;
- }
- }
-
- private boolean isDeltaInBounds(int startAngle, int deltaAngle) {
- return getBoundIfExceeds(startAngle, deltaAngle) == Integer.MIN_VALUE;
- }
-
- private int getBoundIfExceeds(int startAngle, int deltaAngle) {
- if (deltaAngle > 0) {
- // Counterclockwise movement
- if (mThumbCcwBound != Integer.MIN_VALUE &&
- getDelta(startAngle, mThumbCcwBound, true) < deltaAngle) {
- return mThumbCcwBound;
- }
- } else if (deltaAngle < 0) {
- // Clockwise movement, both of these will be negative
- int deltaThumbAndBound = getDelta(startAngle, mThumbCwBound, false);
- if (mThumbCwBound != Integer.MIN_VALUE &&
- deltaThumbAndBound > deltaAngle) {
- // Tapped outside of the bound in that direction
- return mThumbCwBound;
- }
- }
-
- return Integer.MIN_VALUE;
- }
-
- private int getDelta(int startAngle, int endAngle, boolean useDirection, boolean ccw) {
- return useDirection ? getDelta(startAngle, endAngle, ccw) : getDelta(startAngle, endAngle);
- }
-
- /**
- * Gets the smallest delta between two angles, and infers the direction
- * based on the shortest path between the two angles. If going from
- * startAngle to endAngle is counterclockwise, the result will be positive.
- * If it is clockwise, the result will be negative.
- *
- * @param startAngle The start angle.
- * @param endAngle The end angle.
- * @return The difference in angles.
- */
- private int getDelta(int startAngle, int endAngle) {
- int largerAngle, smallerAngle;
- if (endAngle > startAngle) {
- largerAngle = endAngle;
- smallerAngle = startAngle;
- } else {
- largerAngle = startAngle;
- smallerAngle = endAngle;
- }
-
- int delta = largerAngle - smallerAngle;
- if (delta <= PI_INT_MULTIPLIED) {
- // If going clockwise, negate the delta
- return startAngle == largerAngle ? -delta : delta;
- } else {
- // The other direction is the delta we want (it includes the
- // discontinuous 0-2PI angle)
- delta = TWO_PI_INT_MULTIPLIED - delta;
- // If going clockwise, negate the delta
- return startAngle == smallerAngle ? -delta : delta;
- }
- }
-
- /**
- * Gets the delta between two angles in the direction specified.
- *
- * @param startAngle The start angle.
- * @param endAngle The end angle.
- * @param counterClockwise The direction to take when computing the delta.
- * @return The difference in angles in the given direction.
- */
- private int getDelta(int startAngle, int endAngle, boolean counterClockwise) {
- int delta = endAngle - startAngle;
-
- if (!counterClockwise && delta > 0) {
- // Crossed the discontinuous 0/2PI angle, take the leftover slice of
- // the pie and negate it
- return -TWO_PI_INT_MULTIPLIED + delta;
- } else if (counterClockwise && delta < 0) {
- // Crossed the discontinuous 0/2PI angle, take the leftover slice of
- // the pie (and ensure it is positive)
- return TWO_PI_INT_MULTIPLIED + delta;
- } else {
- return delta;
- }
- }
-
- private void onThumbDragStarted(int startAngle) {
- setThumbArrowsVisible(false);
- mThumbDragStartAngle = startAngle;
- mCallback.onZoomRingThumbDraggingStarted();
- }
-
- private void onThumbDragged(int touchAngle, boolean useDirection, boolean ccw) {
- boolean animateThumbToNewAngle = false;
-
- int totalDeltaAngle;
- totalDeltaAngle = getDelta(mPreviousCallbackTickAngle, touchAngle, useDirection, ccw);
- if (totalDeltaAngle >= mFuzzyTickDelta
- || totalDeltaAngle <= -mFuzzyTickDelta) {
-
- if (!useDirection) {
- // Set ccw to match the direction found by getDelta
- ccw = totalDeltaAngle > 0;
- }
-
- /*
- * When the user slides the thumb through the tick that corresponds
- * to a zoom bound, we don't want to abruptly stop there. Instead,
- * let the user slide it to the next tick, and then animate it back
- * to the original zoom bound tick. Because of this, we make sure
- * the delta from the bound is more than halfway to the next tick.
- * We make sure the bound is between the touch and the previous
- * callback to ensure we just passed the bound.
- */
- int oldTouchAngle = touchAngle;
- if (ccw && mThumbCcwBound != Integer.MIN_VALUE) {
- int deltaCcwBoundAndTouch =
- getDelta(mThumbCcwBound, touchAngle, useDirection, true);
- if (deltaCcwBoundAndTouch >= mTickDelta / 2) {
- // The touch has past a bound
- int deltaPreviousCbAndTouch = getDelta(mPreviousCallbackTickAngle,
- touchAngle, useDirection, true);
- if (deltaPreviousCbAndTouch >= deltaCcwBoundAndTouch) {
- // The bound is between the previous callback angle and the touch
- touchAngle = mThumbCcwBound;
- // We're moving the touch BACK to the bound, so opposite direction
- ccw = false;
- }
- }
- } else if (!ccw && mThumbCwBound != Integer.MIN_VALUE) {
- // See block above for general comments
- int deltaCwBoundAndTouch =
- getDelta(mThumbCwBound, touchAngle, useDirection, false);
- if (deltaCwBoundAndTouch <= -mTickDelta / 2) {
- int deltaPreviousCbAndTouch = getDelta(mPreviousCallbackTickAngle,
- touchAngle, useDirection, false);
- /*
- * Both of these will be negative since we got delta in
- * clockwise direction, and we want the magnitude of
- * deltaPreviousCbAndTouch to be greater than the magnitude
- * of deltaCwBoundAndTouch
- */
- if (deltaPreviousCbAndTouch <= deltaCwBoundAndTouch) {
- touchAngle = mThumbCwBound;
- ccw = true;
- }
- }
- }
- if (touchAngle != oldTouchAngle) {
- // We bounded the touch angle
- totalDeltaAngle = getDelta(mPreviousCallbackTickAngle, touchAngle, useDirection, ccw);
- animateThumbToNewAngle = true;
- setMode(MODE_IGNORE_UNTIL_TOUCHES_THUMB);
- }
-
-
- // Prevent it from jumping too far
- if (mEnforceMaxAbsJump) {
- if (totalDeltaAngle <= -MAX_ABS_JUMP_DELTA_ANGLE) {
- totalDeltaAngle = -MAX_ABS_JUMP_DELTA_ANGLE;
- animateThumbToNewAngle = true;
- } else if (totalDeltaAngle >= MAX_ABS_JUMP_DELTA_ANGLE) {
- totalDeltaAngle = MAX_ABS_JUMP_DELTA_ANGLE;
- animateThumbToNewAngle = true;
- }
- }
-
- /*
- * We need to cover the edge case of a user grabbing the thumb,
- * going into the center of the widget, and then coming out from the
- * center to an angle that's slightly below the angle he's trying to
- * hit. If we do int division, we'll end up with one level lower
- * than the one he was going for.
- */
- int deltaLevels = Math.round((float) totalDeltaAngle / mTickDelta);
- if (deltaLevels != 0) {
- boolean canStillZoom = mCallback.onZoomRingThumbDragged(
- deltaLevels, mThumbDragStartAngle, touchAngle);
-
- if (mVibration) {
- // TODO: we're trying the haptics to see how it goes with
- // users, so we're ignoring the settings (for now)
- performHapticFeedback(HapticFeedbackConstants.ZOOM_RING_TICK,
- HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING |
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
- }
-
- // Set the callback angle to the actual angle based on how many delta levels we gave
- mPreviousCallbackTickAngle = getValidAngle(
- mPreviousCallbackTickAngle + (deltaLevels * mTickDelta));
- }
- }
-
- 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);
- } else {
- setThumbAngleAnimated(touchAngle, 0);
- }
- } else {
- setThumbAngleAuto(touchAngle, useDirection, ccw);
- }
- }
-// private void onThumbDragged(int touchAngle, boolean useDirection, boolean ccw) {
-// int deltaPrevCbAndTouch = getDelta(mPreviousCallbackAngle, touchAngle, useDirection, ccw);
-//
-// if (!useDirection) {
-// // Set ccw to match the direction found by getDelta
-// ccw = deltaPrevCbAndTouch > 0;
-// useDirection = true;
-// }
-//
-// boolean animateThumbToNewAngle = false;
-// boolean animationCcw = ccw;
-//
-// if (deltaPrevCbAndTouch >= mFuzzyCallbackThreshold
-// || deltaPrevCbAndTouch <= -mFuzzyCallbackThreshold) {
-//
-// /*
-// * When the user slides the thumb through the tick that corresponds
-// * to a zoom bound, we don't want to abruptly stop there. Instead,
-// * let the user slide it to the next tick, and then animate it back
-// * to the original zoom bound tick. Because of this, we make sure
-// * the delta from the bound is more than halfway to the next tick.
-// * We make sure the bound is between the touch and the previous
-// * callback to ensure we JUST passed the bound.
-// */
-// int oldTouchAngle = touchAngle;
-// if (ccw && mThumbCcwBound != Integer.MIN_VALUE) {
-// int deltaCcwBoundAndTouch =
-// getDelta(mThumbCcwBound, touchAngle, true, ccw);
-// if (deltaCcwBoundAndTouch >= mCallbackThreshold / 2) {
-// // The touch has past far enough from the bound
-// int deltaPreviousCbAndTouch = getDelta(mPreviousCallbackAngle,
-// touchAngle, true, ccw);
-// if (deltaPreviousCbAndTouch >= deltaCcwBoundAndTouch) {
-// // The bound is between the previous callback angle and the touch
-// // Cap to the bound
-// touchAngle = mThumbCcwBound;
-// /*
-// * We're moving the touch BACK to the bound, so animate
-// * back in the opposite direction that passed the bound.
-// */
-// animationCcw = false;
-// }
-// }
-// } else if (!ccw && mThumbCwBound != Integer.MIN_VALUE) {
-// // See block above for general comments
-// int deltaCwBoundAndTouch =
-// getDelta(mThumbCwBound, touchAngle, true, ccw);
-// if (deltaCwBoundAndTouch <= -mCallbackThreshold / 2) {
-// int deltaPreviousCbAndTouch = getDelta(mPreviousCallbackAngle,
-// touchAngle, true, ccw);
-// /*
-// * Both of these will be negative since we got delta in
-// * clockwise direction, and we want the magnitude of
-// * deltaPreviousCbAndTouch to be greater than the magnitude
-// * of deltaCwBoundAndTouch
-// */
-// if (deltaPreviousCbAndTouch <= deltaCwBoundAndTouch) {
-// touchAngle = mThumbCwBound;
-// animationCcw = true;
-// }
-// }
-// }
-// if (touchAngle != oldTouchAngle) {
-// // We bounded the touch angle
-// deltaPrevCbAndTouch = getDelta(mPreviousCallbackAngle, touchAngle, true, ccw);
-// // Animate back to the bound
-// animateThumbToNewAngle = true;
-// // Disallow movement now
-// setMode(MODE_IGNORE_UNTIL_UP);
-// }
-//
-//
-// /*
-// * Prevent it from jumping too far (this could happen if the user
-// * goes through the center)
-// */
-//
-// if (mEnforceMaxAbsJump) {
-// if (deltaPrevCbAndTouch <= -MAX_ABS_JUMP_DELTA_ANGLE) {
-// deltaPrevCbAndTouch = -MAX_ABS_JUMP_DELTA_ANGLE;
-// animateThumbToNewAngle = true;
-// } else if (deltaPrevCbAndTouch >= MAX_ABS_JUMP_DELTA_ANGLE) {
-// deltaPrevCbAndTouch = MAX_ABS_JUMP_DELTA_ANGLE;
-// animateThumbToNewAngle = true;
-// }
-// }
-//
-// /*
-// * We need to cover the edge case of a user grabbing the thumb,
-// * going into the center of the widget, and then coming out from the
-// * center to an angle that's slightly below the angle he's trying to
-// * hit. If we do int division, we'll end up with one level lower
-// * than the one he was going for.
-// */
-// int deltaLevels = Math.round((float) deltaPrevCbAndTouch / mCallbackThreshold);
-// if (deltaLevels != 0) {
-// boolean canStillZoom = mCallback.onZoomRingThumbDragged(
-// deltaLevels, mThumbDragStartAngle, touchAngle);
-//
-// if (mVibration) {
-// // TODO: we're trying the haptics to see how it goes with
-// // users, so we're ignoring the settings (for now)
-// performHapticFeedback(HapticFeedbackConstants.ZOOM_RING_TICK,
-// HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING |
-// HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
-//
-// }
-// // Set the callback angle to the actual angle based on how many delta levels we gave
-// mPreviousCallbackAngle = getValidAngle(
-// mPreviousCallbackAngle + (deltaLevels * mCallbackThreshold));
-// }
-// }
-//
-// if (DRAW_TRAIL) {
-// int deltaAngle = getDelta(mThumbAngle, touchAngle, true, ccw);
-// mAcculumalatedTrailAngle += Math.toDegrees(deltaAngle / (double) RADIAN_INT_MULTIPLIER);
-// }
-//
-// if (animateThumbToNewAngle) {
-// setThumbAngleAnimated(touchAngle, 0, animationCcw);
-// } else {
-// /*
-// * Use regular ccw here because animationCcw will never have been
-// * changed if animateThumbToNewAngle is false
-// */
-// setThumbAngleAuto(touchAngle, true, ccw);
-// }
-// }
-
- private int getValidAngle(int invalidAngle) {
- if (invalidAngle < 0) {
- return (invalidAngle % TWO_PI_INT_MULTIPLIED) + TWO_PI_INT_MULTIPLIED;
- } else if (invalidAngle >= TWO_PI_INT_MULTIPLIED) {
- return invalidAngle % TWO_PI_INT_MULTIPLIED;
- } else {
- return invalidAngle;
- }
- }
-
- private int getClosestTickAngle(int angle) {
- int smallerAngleDistance = angle % mTickDelta;
- int smallerAngle = angle - smallerAngleDistance;
- if (smallerAngleDistance < mTickDelta / 2) {
- // Closer to the smaller angle
- return smallerAngle;
- } else {
- // Closer to the bigger angle (premodding)
- return (smallerAngle + mTickDelta) % TWO_PI_INT_MULTIPLIED;
- }
- }
-
- private void onThumbDragStopped() {
- mCallback.onZoomRingThumbDraggingStopped();
- }
-
- private void onZoomRingMoved(int rawX, int rawY) {
- if (mPreviousWidgetDragX != Integer.MIN_VALUE) {
- int deltaX = rawX - mPreviousWidgetDragX;
- int deltaY = rawY - mPreviousWidgetDragY;
-
- mCallback.onZoomRingMoved(deltaX, deltaY, rawX, rawY);
- }
-
- mPreviousWidgetDragX = rawX;
- mPreviousWidgetDragY = rawY;
- }
-
- @Override
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- super.onWindowFocusChanged(hasWindowFocus);
-
- if (!hasWindowFocus) {
- mCallback.onZoomRingDismissed();
- }
- }
-
- private int getAngle(int localX, int localY) {
- int radians = (int) (Math.atan2(localY, localX) * RADIAN_INT_MULTIPLIER);
-
- // Convert from [-pi,pi] to {0,2pi]
- if (radians < 0) {
- radians = -radians;
- } else if (radians > 0) {
- radians = 2 * PI_INT_MULTIPLIED - radians;
- } else {
- radians = 0;
- }
-
- radians = radians - mZeroAngle;
- return radians >= 0 ? radians : radians + 2 * PI_INT_MULTIPLIED;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- if (mThumbVisible) {
- if (DRAW_TRAIL) {
- mTrail.draw(canvas);
- }
- if ((mThumbArrowsToDraw & THUMB_ARROW_PLUS) != 0) {
- mZoomInArrowDrawable.draw(canvas);
- mZoomInArrowHintDrawable.draw(canvas);
- }
- if ((mThumbArrowsToDraw & THUMB_ARROW_MINUS) != 0) {
- mZoomOutArrowDrawable.draw(canvas);
- mZoomOutArrowHintDrawable.draw(canvas);
- }
- mThumbDrawable.draw(canvas);
- }
- }
-
- private void setThumbArrowsAngle(int angle) {
- int level = -angle * 10000 / ZoomRing.TWO_PI_INT_MULTIPLIED;
- mZoomInArrowDrawable.setLevel(level);
- mZoomOutArrowDrawable.setLevel(level);
-
- // Assume it is a square
- int halfSideLength = mZoomInArrowHintDrawable.getIntrinsicHeight() / 2;
- int unoffsetAngle = angle + mZeroAngle;
-
- int plusCenterX = (int) (Math.cos(1f * (unoffsetAngle - mZoomArrowHintOffsetAngle)
- / RADIAN_INT_MULTIPLIER) * mZoomArrowHintDistance) + mCenterX;
- int plusCenterY = (int) (Math.sin(1f * (unoffsetAngle - mZoomArrowHintOffsetAngle)
- / RADIAN_INT_MULTIPLIER) * mZoomArrowHintDistance) * -1 + mCenterY;
- mZoomInArrowHintDrawable.setBounds(plusCenterX - halfSideLength,
- plusCenterY - halfSideLength,
- plusCenterX + halfSideLength,
- plusCenterY + halfSideLength);
-
- int minusCenterX = (int) (Math.cos(1f * (unoffsetAngle + mZoomArrowHintOffsetAngle)
- / RADIAN_INT_MULTIPLIER) * mZoomArrowHintDistance) + mCenterX;
- int minusCenterY = (int) (Math.sin(1f * (unoffsetAngle + mZoomArrowHintOffsetAngle)
- / RADIAN_INT_MULTIPLIER) * mZoomArrowHintDistance) * -1 + mCenterY;
- mZoomOutArrowHintDrawable.setBounds(minusCenterX - halfSideLength,
- minusCenterY - halfSideLength,
- minusCenterX + halfSideLength,
- minusCenterY + halfSideLength);
- }
-
- void setThumbArrowsVisible(boolean visible) {
- if (visible) {
- mThumbArrowsAlpha = 255;
- int callbackAngle = mPreviousCallbackTickAngle;
- if (callbackAngle < mThumbCwBound - RADIAN_INT_ERROR ||
- callbackAngle > mThumbCwBound + RADIAN_INT_ERROR) {
- mZoomInArrowDrawable.setAlpha(255);
- mZoomInArrowHintDrawable.setAlpha(255);
- mThumbArrowsToDraw |= THUMB_ARROW_PLUS;
- } else {
- mThumbArrowsToDraw &= ~THUMB_ARROW_PLUS;
- }
- if (callbackAngle < mThumbCcwBound - RADIAN_INT_ERROR ||
- callbackAngle > mThumbCcwBound + RADIAN_INT_ERROR) {
- mZoomOutArrowDrawable.setAlpha(255);
- mZoomOutArrowHintDrawable.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)
- mThumbArrowsFadeStartTime = SystemClock.elapsedRealtime();
- onThumbArrowsFadeStep();
- }
- }
-
- private void onThumbArrowsFadeStep() {
- if (mThumbArrowsAlpha <= 0) {
- mThumbArrowsToDraw = 0;
- return;
- }
-
- mThumbArrowsAlpha = (int)
- (255 - (255 * (SystemClock.elapsedRealtime() - mThumbArrowsFadeStartTime)
- / THUMB_ARROWS_FADE_DURATION));
- if (mThumbArrowsAlpha < 0) mThumbArrowsAlpha = 0;
- if ((mThumbArrowsToDraw & THUMB_ARROW_PLUS) != 0) {
- mZoomInArrowDrawable.setAlpha(mThumbArrowsAlpha);
- mZoomInArrowHintDrawable.setAlpha(mThumbArrowsAlpha);
- invalidateDrawable(mZoomInArrowHintDrawable);
- invalidateDrawable(mZoomInArrowDrawable);
- }
- if ((mThumbArrowsToDraw & THUMB_ARROW_MINUS) != 0) {
- mZoomOutArrowDrawable.setAlpha(mThumbArrowsAlpha);
- mZoomOutArrowHintDrawable.setAlpha(mThumbArrowsAlpha);
- invalidateDrawable(mZoomOutArrowHintDrawable);
- invalidateDrawable(mZoomOutArrowDrawable);
- }
-
- if (!mHandler.hasMessages(MSG_THUMB_ARROWS_FADE_STEP)) {
- mHandler.sendEmptyMessage(MSG_THUMB_ARROWS_FADE_STEP);
- }
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- setThumbArrowsAngle(mThumbAngle);
- setThumbArrowsVisible(true);
- }
-
- public interface OnZoomRingCallback {
- void onZoomRingSetMovableHintVisible(boolean visible);
-
- void onZoomRingMovingStarted();
- boolean onZoomRingMoved(int deltaX, int deltaY, int rawX, int rawY);
- void onZoomRingMovingStopped();
-
- void onZoomRingThumbDraggingStarted();
- boolean onZoomRingThumbDragged(int numLevels, int startAngle, int curAngle);
- void onZoomRingThumbDraggingStopped();
-
- void onZoomRingDismissed();
-
- void onUserInteractionStarted();
- void onUserInteractionStopped();
- }
-
- private static void printAngle(String angleName, int angle) {
- Log.d(TAG, angleName + ": " + (long) angle * 180 / PI_INT_MULTIPLIED);
- }
-}
diff --git a/core/java/android/widget/ZoomRingController.java b/core/java/android/widget/ZoomRingController.java
deleted file mode 100644
index 3bf3b22..0000000
--- a/core/java/android/widget/ZoomRingController.java
+++ /dev/null
@@ -1,1383 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.DisplayMetrics;
-import android.view.GestureDetector;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
-
-/**
- * A controller to simplify the use of the zoom ring widget.
- * <p>
- * If you are using this with a custom View, please call
- * {@link #setVisible(boolean) setVisible(false)} from the
- * {@link View#onDetachedFromWindow}.
- *
- * @hide
- */
-public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
- View.OnTouchListener, View.OnKeyListener {
-
- // Temporary methods for different zoom types
- static int getZoomType(Context context) {
- return Settings.System.getInt(context.getContentResolver(), "zoom", 1);
- }
- public static boolean useOldZoom(Context context) {
- return getZoomType(context) == 0;
- }
- private static boolean useThisZoom(Context context) {
- return getZoomType(context) == 1;
- }
-
- /** The duration for the animation to re-center the zoom ring. */
- private static final int RECENTERING_DURATION = 500;
-
- /** The inactivity timeout for the zoom ring. */
- private static final int INACTIVITY_TIMEOUT =
- (int) ViewConfiguration.getZoomControlsTimeout();
-
- /**
- * The delay when the user taps outside to dismiss the zoom ring. This is
- * because the user can do a second-tap to recenter the owner view instead
- * of dismissing the zoom ring.
- */
- private static final int OUTSIDE_TAP_DISMISS_DELAY =
- ViewConfiguration.getDoubleTapTimeout() / 2;
-
- /**
- * When the zoom ring is on the edge, this is the delay before we actually
- * start panning the owner.
- * @see #mInitiatePanGap
- */
- private static final int INITIATE_PAN_DELAY = 300;
-
- /**
- * While already panning, if the zoom ring remains this close to an edge,
- * the owner will continue to be panned.
- */
- private int mPanGap;
-
- /** To begin a pan, the zoom ring must be this close to an edge. */
- private int mInitiatePanGap;
-
- /** Initialized from ViewConfiguration. */
- private int mScaledTouchSlop;
-
- /**
- * The setting name that tracks whether we've shown the zoom ring toast.
- */
- private static final String SETTING_NAME_SHOWN_TOAST = "shown_zoom_ring_toast";
-
- private Context mContext;
- private WindowManager mWindowManager;
-
- /**
- * The view that is being zoomed by this zoom ring.
- */
- private View mOwnerView;
-
- /**
- * The bounds of the owner view in global coordinates. This is recalculated
- * each time the zoom ring is shown.
- */
- private Rect mOwnerViewBounds = new Rect();
-
- /**
- * The container that is added as a window.
- */
- private FrameLayout mContainer;
- private LayoutParams mContainerLayoutParams;
-
- /**
- * The view (or null) that should receive touch events. This will get set if
- * the touch down hits the container. It will be reset on the touch up.
- */
- private View mTouchTargetView;
- /**
- * The {@link #mTouchTargetView}'s location in window, set on touch down.
- */
- private int[] mTouchTargetLocationInWindow = new int[2];
- /**
- * If the zoom ring is dismissed but the user is still in a touch
- * interaction, we set this to true. This will ignore all touch events until
- * up/cancel, and then set the owner's touch listener to null.
- */
- private boolean mReleaseTouchListenerOnUp;
-
-
- /*
- * Tap-drag is an interaction where the user first taps and then (quickly)
- * does the clockwise or counter-clockwise drag. In reality, this is: (down,
- * up, down, move in circles, up). This differs from the usual events of:
- * (down, up, down, up, down, move in circles, up). While the only
- * difference is the omission of an (up, down), for power-users this is a
- * pretty big improvement as it now only requires them to focus on the
- * screen once (for the first tap down) instead of twice (for the first tap
- * down and then to grab the thumb).
- */
- /** The X where the tap-drag started. */
- private int mTapDragStartX;
- /** The Y where the tap-drag started. */
- private int mTapDragStartY;
-
- /** The controller is idle */
- private static final int TOUCH_MODE_IDLE = 0;
- /**
- * In the middle of a second-tap interaction, waiting for either an up-touch
- * or the user to start dragging to go into tap-drag mode.
- */
- private static final int TOUCH_MODE_WAITING_FOR_TAP_DRAG_MOVEMENT = 2;
- /** In the middle of a tap-drag. */
- private static final int TOUCH_MODE_FORWARDING_FOR_TAP_DRAG = 3;
- private int mTouchMode;
-
- /** Whether the zoom ring is visible. */
- private boolean mIsZoomRingVisible;
-
- private ZoomRing mZoomRing;
- /** Cached width of the zoom ring. */
- private int mZoomRingWidth;
- /** Cached height of the zoom ring. */
- private int mZoomRingHeight;
-
- /** Invokes panning of owner view if the zoom ring is touching an edge. */
- private Panner mPanner;
- /** The time when the zoom ring first touched the edge. */
- private long mTouchingEdgeStartTime;
- /** Whether the user has already initiated the panning. */
- private boolean mPanningInitiated;
-
- /**
- * When the finger moves the zoom ring to an edge, this is the horizontal
- * accumulator for how much the finger has moved off of its original touch
- * point on the zoom ring (OOB = out-of-bounds). If < 0, the finger has
- * moved that many px to the left of its original touch point on the ring.
- */
- private int mMovingZoomRingOobX;
- /** Vertical accumulator, see {@link #mMovingZoomRingOobX} */
- private int mMovingZoomRingOobY;
-
- /** Arrows that hint that the zoom ring is movable. */
- private ImageView mPanningArrows;
- /** The animation shown when the panning arrows are being shown. */
- private Animation mPanningArrowsEnterAnimation;
- /** The animation shown when the panning arrows are being hidden. */
- private Animation mPanningArrowsExitAnimation;
-
- /**
- * Temporary rectangle, only use from the UI thread (and ideally don't rely
- * on it being unused across many method calls.)
- */
- private Rect mTempRect = new Rect();
-
- private OnZoomListener mCallback;
-
- /**
- * When the zoom ring is centered on screen, this will be the x value used
- * for the container's layout params.
- */
- private int mCenteredContainerX = Integer.MIN_VALUE;
-
- /**
- * When the zoom ring is centered on screen, this will be the y value used
- * for the container's layout params.
- */
- private int mCenteredContainerY = Integer.MIN_VALUE;
-
- /**
- * Scroller used to re-center the zoom ring if the user had dragged it to a
- * corner and then double-taps any point on the owner view (the owner view
- * will center the double-tapped point, but we should re-center the zoom
- * ring).
- * <p>
- * The (x,y) of the scroller is the (x,y) of the container's layout params.
- */
- private Scroller mScroller;
-
- /**
- * When showing the zoom ring, we add the view as a new window. However,
- * there is logic that needs to know the size of the zoom ring which is
- * determined after it's laid out. Therefore, we must post this logic onto
- * the UI thread so it will be exceuted AFTER the layout. This is the logic.
- */
- private Runnable mPostedVisibleInitializer;
-
- /**
- * Only touch from the main thread.
- */
- private static Dialog sTutorialDialog;
- private static long sTutorialShowTime;
- private static final int TUTORIAL_MIN_DISPLAY_TIME = 2000;
-
- private IntentFilter mConfigurationChangedFilter =
- new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
-
- /** Listens for configuration changes so we can make sure we're still in a reasonable state. */
- private BroadcastReceiver mConfigurationChangedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!mIsZoomRingVisible) return;
-
- mHandler.removeMessages(MSG_POST_CONFIGURATION_CHANGED);
- mHandler.sendEmptyMessage(MSG_POST_CONFIGURATION_CHANGED);
- }
- };
-
- /** Keeps the scroller going (or starts it). */
- private static final int MSG_SCROLLER_STEP = 1;
- /** When configuration changes, this is called after the UI thread is idle. */
- private static final int MSG_POST_CONFIGURATION_CHANGED = 2;
- /** Used to delay the zoom ring dismissal. */
- private static final int MSG_DISMISS_ZOOM_RING = 3;
-
- /**
- * If setVisible(true) is called and the owner view's window token is null,
- * we delay the setVisible(true) call until it is not null.
- */
- private static final int MSG_POST_SET_VISIBLE = 4;
-
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_SCROLLER_STEP:
- onScrollerStep();
- break;
-
- case MSG_POST_CONFIGURATION_CHANGED:
- onPostConfigurationChanged();
- break;
-
- case MSG_DISMISS_ZOOM_RING:
- setVisible(false);
- break;
-
- case MSG_POST_SET_VISIBLE:
- if (mOwnerView.getWindowToken() == null) {
- // Doh, it is still null, throw an exception
- throw new IllegalArgumentException(
- "Cannot make the zoom ring visible if the owner view is " +
- "not attached to a window.");
- }
- setVisible(true);
- break;
- }
-
- }
- };
-
- public ZoomRingController(Context context, View ownerView) {
- mContext = context;
- mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-
- mPanner = new Panner();
- mOwnerView = ownerView;
-
- mZoomRing = new ZoomRing(context);
- mZoomRing.setId(com.android.internal.R.id.zoomControls);
- mZoomRing.setLayoutParams(new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- FrameLayout.LayoutParams.WRAP_CONTENT,
- Gravity.CENTER));
- mZoomRing.setCallback(this);
-
- createPanningArrows();
-
- mContainerLayoutParams = new LayoutParams();
- mContainerLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
- mContainerLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCHABLE |
- LayoutParams.FLAG_NOT_FOCUSABLE |
- LayoutParams.FLAG_LAYOUT_NO_LIMITS;
- mContainerLayoutParams.height = LayoutParams.WRAP_CONTENT;
- mContainerLayoutParams.width = LayoutParams.WRAP_CONTENT;
- mContainerLayoutParams.type = LayoutParams.TYPE_APPLICATION_PANEL;
- mContainerLayoutParams.format = PixelFormat.TRANSPARENT;
- mContainerLayoutParams.windowAnimations = com.android.internal.R.style.Animation_ZoomRing;
-
- mContainer = new FrameLayout(context);
- mContainer.setLayoutParams(mContainerLayoutParams);
- mContainer.setMeasureAllChildren(true);
-
- mContainer.addView(mZoomRing);
- mContainer.addView(mPanningArrows);
-
- mScroller = new Scroller(context, new DecelerateInterpolator());
-
- ViewConfiguration vc = ViewConfiguration.get(context);
- mScaledTouchSlop = vc.getScaledTouchSlop();
-
- float density = context.getResources().getDisplayMetrics().density;
- mPanGap = (int) (20 * density);
- mInitiatePanGap = (int) (10 * density);
- }
-
- private void createPanningArrows() {
- mPanningArrows = new ImageView(mContext);
- mPanningArrows.setImageDrawable(mZoomRing.getPanningArrowsDrawable());
- mPanningArrows.setLayoutParams(new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- FrameLayout.LayoutParams.WRAP_CONTENT,
- Gravity.CENTER));
- mPanningArrows.setVisibility(View.INVISIBLE);
-
- mPanningArrowsEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.fade_in);
- mPanningArrowsExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.fade_out);
- }
-
- /**
- * Sets the angle (in radians) between ticks. This is also the angle a user
- * must move the thumb in order for the client to get a callback. Once there
- * is a callback, the accumulator resets. For example, if you set this to
- * PI/6, it will give a callback every time the user moves PI/6 amount on
- * the ring.
- *
- * @param angle The angle for the callback threshold, in radians
- */
- public void setTickDelta(float angle) {
- mZoomRing.setTickDelta((int) (angle * ZoomRing.RADIAN_INT_MULTIPLIER));
- }
-
- /**
- * Sets a drawable for the zoom ring track.
- *
- * @param drawable The drawable to use for the track.
- * @hide Need a better way of doing this, but this one-off for browser so it
- * can have its final look for the usability study
- */
- public void setTrackDrawable(int drawable) {
- mZoomRing.setBackgroundResource(drawable);
- }
-
- /**
- * Sets the callback for the zoom ring controller.
- *
- * @param callback The callback.
- */
- public void setCallback(OnZoomListener callback) {
- mCallback = callback;
- }
-
- public void setVibration(boolean vibrate) {
- mZoomRing.setVibration(vibrate);
- }
-
- public void setThumbAngle(float angle) {
- mZoomRing.setThumbAngle((int) (angle * ZoomRing.RADIAN_INT_MULTIPLIER));
- }
-
- public void setThumbAngleAnimated(float angle) {
- mZoomRing.setThumbAngleAnimated((int) (angle * ZoomRing.RADIAN_INT_MULTIPLIER), 0);
- }
-
- public void setThumbVisible(boolean thumbVisible) {
- mZoomRing.setThumbVisible(thumbVisible);
- }
-
- public void setThumbClockwiseBound(float angle) {
- mZoomRing.setThumbClockwiseBound(angle >= 0 ?
- (int) (angle * ZoomRing.RADIAN_INT_MULTIPLIER) :
- Integer.MIN_VALUE);
- }
-
- public void setThumbCounterclockwiseBound(float angle) {
- mZoomRing.setThumbCounterclockwiseBound(angle >= 0 ?
- (int) (angle * ZoomRing.RADIAN_INT_MULTIPLIER) :
- Integer.MIN_VALUE);
- }
-
- public boolean isVisible() {
- return mIsZoomRingVisible;
- }
-
- public void setVisible(boolean visible) {
-
- if (!useThisZoom(mContext)) return;
-
- if (visible) {
- if (mOwnerView.getWindowToken() == null) {
- /*
- * We need a window token to show ourselves, maybe the owner's
- * window hasn't been created yet but it will have been by the
- * time the looper is idle, so post the setVisible(true) call.
- */
- if (!mHandler.hasMessages(MSG_POST_SET_VISIBLE)) {
- mHandler.sendEmptyMessage(MSG_POST_SET_VISIBLE);
- }
- return;
- }
-
- dismissZoomRingDelayed(INACTIVITY_TIMEOUT);
- } else {
- mPanner.stop();
- }
-
- if (mIsZoomRingVisible == visible) {
- return;
- }
- mIsZoomRingVisible = visible;
-
- if (visible) {
- if (mContainerLayoutParams.token == null) {
- mContainerLayoutParams.token = mOwnerView.getWindowToken();
- }
-
- mWindowManager.addView(mContainer, mContainerLayoutParams);
-
- if (mPostedVisibleInitializer == null) {
- mPostedVisibleInitializer = new Runnable() {
- public void run() {
- refreshPositioningVariables();
- resetZoomRing();
- refreshContainerLayout();
-
- if (mCallback != null) {
- mCallback.onVisibilityChanged(true);
- }
- }
- };
- }
-
- mPanningArrows.setAnimation(null);
-
- mHandler.post(mPostedVisibleInitializer);
-
- // Handle configuration changes when visible
- mContext.registerReceiver(mConfigurationChangedReceiver, mConfigurationChangedFilter);
-
- // Steal key/touches events from the owner
- mOwnerView.setOnKeyListener(this);
- mOwnerView.setOnTouchListener(this);
- mReleaseTouchListenerOnUp = false;
-
- } else {
- // Don't want to steal any more keys/touches
- mOwnerView.setOnKeyListener(null);
- if (mTouchTargetView != null) {
- // We are still stealing the touch events for this touch
- // sequence, so release the touch listener later
- mReleaseTouchListenerOnUp = true;
- } 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);
- }
- }
-
- }
-
- private void refreshContainerLayout() {
- if (mIsZoomRingVisible) {
- mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams);
- }
- }
-
- /**
- * Returns the container of the zoom ring widget. The client can add views
- * here to be shown alongside the zoom ring. See {@link #getZoomRingId()}.
- * <p>
- * Notes:
- * <ul>
- * <li> The controller dispatches touch events differently than the regular view
- * framework.
- * <li> Please ensure you set your view to INVISIBLE not GONE when hiding it.
- * </ul>
- *
- * @return The layout used by the container.
- */
- public FrameLayout getContainer() {
- return mContainer;
- }
-
- /**
- * Returns the id of the zoom ring widget.
- *
- * @return The id of the zoom ring widget.
- */
- public int getZoomRingId() {
- return mZoomRing.getId();
- }
-
- private void dismissZoomRingDelayed(int delay) {
- mHandler.removeMessages(MSG_DISMISS_ZOOM_RING);
- mHandler.sendEmptyMessageDelayed(MSG_DISMISS_ZOOM_RING, delay);
- }
-
- private void resetZoomRing() {
- mScroller.abortAnimation();
-
- mContainerLayoutParams.x = mCenteredContainerX;
- mContainerLayoutParams.y = mCenteredContainerY;
-
- // Reset the thumb
- mZoomRing.resetThumbAngle();
- }
-
- /**
- * Should be called by the client for each event belonging to the second tap
- * (the down, move, up, and cancel events).
- * <p>
- * In most cases, the client can use a {@link GestureDetector} and forward events from
- * {@link GestureDetector.OnDoubleTapListener#onDoubleTapEvent(MotionEvent)}.
- *
- * @param event The event belonging to the second tap.
- * @return Whether the event was consumed.
- */
- public boolean handleDoubleTapEvent(MotionEvent event) {
- if (!useThisZoom(mContext)) return false;
-
- 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();
- int y = (int) event.getY();
-
- refreshPositioningVariables();
- setVisible(true);
- centerPoint(x, y);
- ensureZoomRingIsCentered();
-
- // Tap drag mode stuff
- mTapDragStartX = x;
- mTapDragStartY = y;
-
- } else if (action == MotionEvent.ACTION_CANCEL) {
- mTouchMode = TOUCH_MODE_IDLE;
-
- } else { // action is move or up
- switch (mTouchMode) {
- case TOUCH_MODE_WAITING_FOR_TAP_DRAG_MOVEMENT: {
- switch (action) {
- case MotionEvent.ACTION_MOVE:
- int x = (int) event.getX();
- int y = (int) event.getY();
- if (Math.abs(x - mTapDragStartX) > mScaledTouchSlop ||
- Math.abs(y - mTapDragStartY) >
- mScaledTouchSlop) {
- mZoomRing.setTapDragMode(true, x, y);
- mTouchMode = TOUCH_MODE_FORWARDING_FOR_TAP_DRAG;
- setTouchTargetView(mZoomRing);
- }
- return true;
-
- case MotionEvent.ACTION_UP:
- mTouchMode = TOUCH_MODE_IDLE;
- break;
- }
- break;
- }
-
- case TOUCH_MODE_FORWARDING_FOR_TAP_DRAG: {
- switch (action) {
- case MotionEvent.ACTION_MOVE:
- giveTouchToZoomRing(event);
- return true;
-
- case MotionEvent.ACTION_UP:
- mTouchMode = TOUCH_MODE_IDLE;
-
- /*
- * This is a power-user feature that only shows the
- * zoom while the user is performing the tap-drag.
- * That means once it is released, the zoom ring
- * should disappear.
- */
- mZoomRing.setTapDragMode(false, (int) event.getX(), (int) event.getY());
- dismissZoomRingDelayed(0);
- break;
- }
- break;
- }
- }
- }
-
- return true;
- }
-
- private void ensureZoomRingIsCentered() {
- LayoutParams lp = mContainerLayoutParams;
-
- if (lp.x != mCenteredContainerX || lp.y != mCenteredContainerY) {
- int width = mContainer.getWidth();
- int height = mContainer.getHeight();
- mScroller.startScroll(lp.x, lp.y, mCenteredContainerX - lp.x,
- mCenteredContainerY - lp.y, RECENTERING_DURATION);
- mHandler.sendEmptyMessage(MSG_SCROLLER_STEP);
- }
- }
-
- private void refreshPositioningVariables() {
- mZoomRingWidth = mZoomRing.getWidth();
- mZoomRingHeight = mZoomRing.getHeight();
-
- // Calculate the owner view's bounds
- mOwnerView.getGlobalVisibleRect(mOwnerViewBounds);
-
- // Get the center
- Gravity.apply(Gravity.CENTER, mContainer.getWidth(), mContainer.getHeight(),
- mOwnerViewBounds, mTempRect);
- mCenteredContainerX = mTempRect.left;
- mCenteredContainerY = mTempRect.top;
- }
-
- /**
- * Centers the point (in owner view's coordinates).
- */
- private void centerPoint(int x, int y) {
- if (mCallback != null) {
- mCallback.onCenter(x, y);
- }
- }
-
- private void giveTouchToZoomRing(MotionEvent event) {
- int rawX = (int) event.getRawX();
- int rawY = (int) event.getRawY();
- int x = rawX - mContainerLayoutParams.x - mZoomRing.getLeft();
- int y = rawY - mContainerLayoutParams.y - mZoomRing.getTop();
- mZoomRing.handleTouch(event.getAction(), event.getEventTime(), x, y, rawX, rawY);
- }
-
- /** @hide */
- public void onZoomRingSetMovableHintVisible(boolean visible) {
- setPanningArrowsVisible(visible);
- }
-
- /** @hide */
- public void onUserInteractionStarted() {
- mHandler.removeMessages(MSG_DISMISS_ZOOM_RING);
- }
-
- /** @hide */
- public void onUserInteractionStopped() {
- dismissZoomRingDelayed(INACTIVITY_TIMEOUT);
- }
-
- /** @hide */
- public void onZoomRingMovingStarted() {
- mScroller.abortAnimation();
- mTouchingEdgeStartTime = 0;
- mMovingZoomRingOobX = 0;
- mMovingZoomRingOobY = 0;
- if (mCallback != null) {
- mCallback.onBeginPan();
- }
- }
-
- private void setPanningArrowsVisible(boolean visible) {
- mPanningArrows.startAnimation(visible ? mPanningArrowsEnterAnimation
- : mPanningArrowsExitAnimation);
- mPanningArrows.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- }
-
- /** @hide */
- public boolean onZoomRingMoved(int deltaX, int deltaY, int rawX, int rawY) {
-
- if (mMovingZoomRingOobX != 0) {
- /*
- * The finger has moved off the point where it originally touched
- * the zidget.
- */
- boolean wasOobLeft = mMovingZoomRingOobX < 0;
- mMovingZoomRingOobX += deltaX;
- if ((wasOobLeft && mMovingZoomRingOobX > 0) ||
- (!wasOobLeft && mMovingZoomRingOobX < 0)) {
- /*
- * Woot, the finger is back on the original point. Infact, it
- * went PAST its original point, so take the amount it passed
- * and use that as the delta to move the zoom ring.
- */
- deltaX = mMovingZoomRingOobX;
- // No longer out-of-bounds, reset
- mMovingZoomRingOobX = 0;
- } else {
- // The finger is still not back, eat this movement
- deltaX = 0;
- }
- }
-
- if (mMovingZoomRingOobY != 0) {
- // See above for comments
- boolean wasOobUp = mMovingZoomRingOobY < 0;
- mMovingZoomRingOobY += deltaY;
- if ((wasOobUp && mMovingZoomRingOobY > 0) || (!wasOobUp && mMovingZoomRingOobY < 0)) {
- deltaY = mMovingZoomRingOobY;
- mMovingZoomRingOobY = 0;
- } else {
- deltaY = 0;
- }
- }
-
- WindowManager.LayoutParams lp = mContainerLayoutParams;
- Rect ownerBounds = mOwnerViewBounds;
-
- int zoomRingLeft = mZoomRing.getLeft();
- int zoomRingTop = mZoomRing.getTop();
-
- int newX = lp.x + deltaX;
- int newZoomRingX = newX + zoomRingLeft;
- newZoomRingX = (newZoomRingX <= ownerBounds.left) ? ownerBounds.left :
- (newZoomRingX + mZoomRingWidth > ownerBounds.right) ?
- ownerBounds.right - mZoomRingWidth : newZoomRingX;
- lp.x = newZoomRingX - zoomRingLeft;
-
- int newY = lp.y + deltaY;
- int newZoomRingY = newY + zoomRingTop;
- newZoomRingY = (newZoomRingY <= ownerBounds.top) ? ownerBounds.top :
- (newZoomRingY + mZoomRingHeight > ownerBounds.bottom) ?
- ownerBounds.bottom - mZoomRingHeight : newZoomRingY;
- lp.y = newZoomRingY - zoomRingTop;
-
- refreshContainerLayout();
-
- // Check for pan
- boolean horizontalPanning = true;
- int leftGap = newZoomRingX - ownerBounds.left;
- if (leftGap < mPanGap) {
- if (leftGap == 0 && deltaX != 0 && mMovingZoomRingOobX == 0) {
- // Future moves in this direction should be accumulated in mMovingZoomRingOobX
- mMovingZoomRingOobX = deltaX / Math.abs(deltaX);
- }
- if (shouldPan(leftGap)) {
- mPanner.setHorizontalStrength(-getStrengthFromGap(leftGap));
- }
- } else {
- int rightGap = ownerBounds.right - (lp.x + mZoomRingWidth + zoomRingLeft);
- if (rightGap < mPanGap) {
- if (rightGap == 0 && deltaX != 0 && mMovingZoomRingOobX == 0) {
- mMovingZoomRingOobX = deltaX / Math.abs(deltaX);
- }
- if (shouldPan(rightGap)) {
- mPanner.setHorizontalStrength(getStrengthFromGap(rightGap));
- }
- } else {
- mPanner.setHorizontalStrength(0);
- horizontalPanning = false;
- }
- }
-
- int topGap = newZoomRingY - ownerBounds.top;
- if (topGap < mPanGap) {
- if (topGap == 0 && deltaY != 0 && mMovingZoomRingOobY == 0) {
- mMovingZoomRingOobY = deltaY / Math.abs(deltaY);
- }
- if (shouldPan(topGap)) {
- mPanner.setVerticalStrength(-getStrengthFromGap(topGap));
- }
- } else {
- int bottomGap = ownerBounds.bottom - (lp.y + mZoomRingHeight + zoomRingTop);
- if (bottomGap < mPanGap) {
- if (bottomGap == 0 && deltaY != 0 && mMovingZoomRingOobY == 0) {
- mMovingZoomRingOobY = deltaY / Math.abs(deltaY);
- }
- if (shouldPan(bottomGap)) {
- mPanner.setVerticalStrength(getStrengthFromGap(bottomGap));
- }
- } else {
- mPanner.setVerticalStrength(0);
- if (!horizontalPanning) {
- // Neither are panning, reset any timer to start pan mode
- mTouchingEdgeStartTime = 0;
- mPanningInitiated = false;
- mPanner.stop();
- }
- }
- }
-
- return true;
- }
-
- private boolean shouldPan(int gap) {
- if (mPanningInitiated) return true;
-
- if (gap < mInitiatePanGap) {
- long time = SystemClock.elapsedRealtime();
- if (mTouchingEdgeStartTime != 0 &&
- mTouchingEdgeStartTime + INITIATE_PAN_DELAY < time) {
- mPanningInitiated = true;
- return true;
- } else if (mTouchingEdgeStartTime == 0) {
- mTouchingEdgeStartTime = time;
- } else {
- }
- } else {
- // Moved away from the initiate pan gap, so reset the timer
- mTouchingEdgeStartTime = 0;
- }
- return false;
- }
-
- /** @hide */
- public void onZoomRingMovingStopped() {
- mPanner.stop();
- setPanningArrowsVisible(false);
- if (mCallback != null) {
- mCallback.onEndPan();
- }
- }
-
- private int getStrengthFromGap(int gap) {
- return gap > mPanGap ? 0 :
- (mPanGap - gap) * 100 / mPanGap;
- }
-
- /** @hide */
- public void onZoomRingThumbDraggingStarted() {
- if (mCallback != null) {
- mCallback.onBeginDrag();
- }
- }
-
- /** @hide */
- public boolean onZoomRingThumbDragged(int numLevels, int startAngle, int curAngle) {
- if (mCallback != null) {
- int deltaZoomLevel = -numLevels;
-
- return mCallback.onDragZoom(deltaZoomLevel,
- getZoomRingCenterXInOwnerCoordinates(),
- getZoomRingCenterYInOwnerCoordinates(),
- (float) startAngle / ZoomRing.RADIAN_INT_MULTIPLIER,
- (float) curAngle / ZoomRing.RADIAN_INT_MULTIPLIER);
- }
-
- return false;
- }
-
- private int getZoomRingCenterXInOwnerCoordinates() {
- int globalZoomCenterX = mContainerLayoutParams.x + mZoomRing.getLeft() +
- mZoomRingWidth / 2;
- return globalZoomCenterX - mOwnerViewBounds.left;
- }
-
- private int getZoomRingCenterYInOwnerCoordinates() {
- int globalZoomCenterY = mContainerLayoutParams.y + mZoomRing.getTop() +
- mZoomRingHeight / 2;
- return globalZoomCenterY - mOwnerViewBounds.top;
- }
-
- /** @hide */
- public void onZoomRingThumbDraggingStopped() {
- if (mCallback != null) {
- mCallback.onEndDrag();
- }
- }
-
- /** @hide */
- public void onZoomRingDismissed() {
- mHandler.removeMessages(MSG_DISMISS_ZOOM_RING);
- setVisible(false);
- }
-
- /** @hide */
- public void onRingDown(int tickAngle, int touchAngle) {
- }
-
- /** @hide */
- public boolean onTouch(View v, MotionEvent event) {
- if (sTutorialDialog != null && sTutorialDialog.isShowing() &&
- SystemClock.elapsedRealtime() - sTutorialShowTime >= TUTORIAL_MIN_DISPLAY_TIME) {
- finishZoomTutorial();
- }
-
- int action = event.getAction();
-
- if (mReleaseTouchListenerOnUp) {
- // 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;
- }
-
- // Eat this event
- return true;
- }
-
- View targetView = mTouchTargetView;
-
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- targetView = getViewForTouch((int) event.getRawX(), (int) event.getRawY());
- setTouchTargetView(targetView);
- break;
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- setTouchTargetView(null);
- break;
- }
-
- if (targetView != null) {
- // The upperleft corner of the target view in raw coordinates
- int targetViewRawX = mContainerLayoutParams.x + mTouchTargetLocationInWindow[0];
- int targetViewRawY = mContainerLayoutParams.y + mTouchTargetLocationInWindow[1];
-
- MotionEvent containerEvent = MotionEvent.obtain(event);
- // Convert the motion event into the target view's coordinates (from
- // owner view's coordinates)
- containerEvent.offsetLocation(mOwnerViewBounds.left - targetViewRawX,
- mOwnerViewBounds.top - targetViewRawY);
- boolean retValue = targetView.dispatchTouchEvent(containerEvent);
- containerEvent.recycle();
- return retValue;
-
- } else {
-// dismissZoomRingDelayed(ZOOM_CONTROLS_TIMEOUT);
- if (action == MotionEvent.ACTION_DOWN) {
- dismissZoomRingDelayed(OUTSIDE_TAP_DISMISS_DELAY);
- }
-
- return false;
- }
- }
-
- 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.
- *
- * @param rawX The raw X.
- * @param rawY The raw Y.
- * @return The view that should receive the touches, or null if there is not one.
- */
- private View getViewForTouch(int rawX, int rawY) {
- // Check to see if it is touching the ring
- int containerCenterX = mContainerLayoutParams.x + mContainer.getWidth() / 2;
- int containerCenterY = mContainerLayoutParams.y + mContainer.getHeight() / 2;
- int distanceFromCenterX = rawX - containerCenterX;
- int distanceFromCenterY = rawY - containerCenterY;
- int zoomRingRadius = mZoomRing.getTrackOuterRadius();
- if (distanceFromCenterX * distanceFromCenterX +
- distanceFromCenterY * distanceFromCenterY <=
- zoomRingRadius * zoomRingRadius) {
- return mZoomRing;
- }
-
- // Check to see if it is touching any other clickable View.
- // Reverse order so the child drawn on top gets first dibs.
- int containerCoordsX = rawX - mContainerLayoutParams.x;
- int containerCoordsY = rawY - mContainerLayoutParams.y;
- Rect frame = mTempRect;
- for (int i = mContainer.getChildCount() - 1; i >= 0; i--) {
- View child = mContainer.getChildAt(i);
- if (child == mZoomRing || child.getVisibility() != View.VISIBLE ||
- !child.isClickable()) {
- continue;
- }
-
- child.getHitRect(frame);
- if (frame.contains(containerCoordsX, containerCoordsY)) {
- return child;
- }
- }
-
- return null;
- }
-
- /**
- * Steals key events from the owner view.
- *
- * @hide
- */
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- // Eat these
- return true;
-
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- // Keep the zoom alive a little longer
- dismissZoomRingDelayed(INACTIVITY_TIMEOUT);
- // They started zooming, hide the thumb arrows
- mZoomRing.setThumbArrowsVisible(false);
-
- if (mCallback != null && event.getAction() == KeyEvent.ACTION_DOWN) {
- mCallback.onSimpleZoom(keyCode == KeyEvent.KEYCODE_DPAD_UP,
- getZoomRingCenterXInOwnerCoordinates(),
- getZoomRingCenterYInOwnerCoordinates());
- }
-
- return true;
- }
-
- return false;
- }
-
- private void onScrollerStep() {
- if (!mScroller.computeScrollOffset() || !mIsZoomRingVisible) return;
-
- mContainerLayoutParams.x = mScroller.getCurrX();
- mContainerLayoutParams.y = mScroller.getCurrY();
- refreshContainerLayout();
-
- mHandler.sendEmptyMessage(MSG_SCROLLER_STEP);
- }
-
- private void onPostConfigurationChanged() {
- dismissZoomRingDelayed(INACTIVITY_TIMEOUT);
- refreshPositioningVariables();
- ensureZoomRingIsCentered();
- }
-
- /*
- * This is static so Activities can call this instead of the Views
- * (Activities usually do not have a reference to the ZoomRingController
- * instance.)
- */
- /**
- * Shows a "tutorial" (some text) to the user teaching her the new zoom
- * invocation method. Must call from the main thread.
- * <p>
- * It checks the global system setting to ensure this has not been seen
- * before. Furthermore, if the application does not have privilege to write
- * to the system settings, it will store this bit locally in a shared
- * preference.
- *
- * @hide This should only be used by our main apps--browser, maps, and
- * gallery
- */
- public static void showZoomTutorialOnce(Context context) {
- ContentResolver cr = context.getContentResolver();
- if (Settings.System.getInt(cr, SETTING_NAME_SHOWN_TOAST, 0) == 1) {
- return;
- }
-
- SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE);
- if (sp.getInt(SETTING_NAME_SHOWN_TOAST, 0) == 1) {
- return;
- }
-
- if (sTutorialDialog != null && sTutorialDialog.isShowing()) {
- sTutorialDialog.dismiss();
- }
-
- LayoutInflater layoutInflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- TextView textView = (TextView) layoutInflater.inflate(
- com.android.internal.R.layout.alert_dialog_simple_text, null)
- .findViewById(android.R.id.text1);
- textView.setText(com.android.internal.R.string.tutorial_double_tap_to_zoom_message_short);
-
- sTutorialDialog = new AlertDialog.Builder(context)
- .setView(textView)
- .setIcon(0)
- .create();
-
- Window window = sTutorialDialog.getWindow();
- window.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
- window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND |
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
-
- sTutorialDialog.show();
- sTutorialShowTime = SystemClock.elapsedRealtime();
- }
-
- /** @hide Should only be used by Android platform apps */
- public static void finishZoomTutorial(Context context, boolean userNotified) {
- if (sTutorialDialog == null) return;
-
- sTutorialDialog.dismiss();
- sTutorialDialog = null;
-
- // Record that they have seen the tutorial
- if (userNotified) {
- try {
- Settings.System.putInt(context.getContentResolver(), SETTING_NAME_SHOWN_TOAST, 1);
- } catch (SecurityException e) {
- /*
- * The app does not have permission to clear this global flag, make
- * sure the user does not see the message when he comes back to this
- * same app at least.
- */
- SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE);
- sp.edit().putInt(SETTING_NAME_SHOWN_TOAST, 1).commit();
- }
- }
- }
-
- /** @hide Should only be used by Android platform apps */
- public void finishZoomTutorial() {
- finishZoomTutorial(mContext, true);
- }
-
- /**
- * Sets the initial velocity of a pan.
- *
- * @param startVelocity The initial velocity to move the owner view, in
- * pixels per second.
- */
- public void setPannerStartVelocity(float startVelocity) {
- mPanner.mStartVelocity = startVelocity;
- }
-
- /**
- * Sets the accelartion of the pan.
- *
- * @param acceleration The acceleration, in pixels per second squared.
- */
- public void setPannerAcceleration(float acceleration) {
- mPanner.mAcceleration = acceleration;
- }
-
- /**
- * Sets the maximum velocity of a pan.
- *
- * @param maxVelocity The max velocity to move the owner view, in pixels per
- * second.
- */
- public void setPannerMaxVelocity(float maxVelocity) {
- mPanner.mMaxVelocity = maxVelocity;
- }
-
- /**
- * Sets the duration before acceleration will be applied.
- *
- * @param duration The duration, in milliseconds.
- */
- 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;
-
- private final Handler mUiHandler = new Handler();
-
- private int mVerticalStrength;
- private int mHorizontalStrength;
-
- private boolean mStopping;
-
- /** The time this current pan started. */
- private long mStartTime;
-
- /** 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) {
- start();
- } else if (mVerticalStrength == 0 && horizontalStrength == 0) {
- stop();
- }
-
- mHorizontalStrength = horizontalStrength;
- mStopping = false;
- }
-
- /** -100 (full up) to 0 (none) to 100 (full down) */
- public void setVerticalStrength(int verticalStrength) {
- if (mHorizontalStrength == 0 && mVerticalStrength == 0 && verticalStrength != 0) {
- start();
- } else if (mHorizontalStrength == 0 && verticalStrength == 0) {
- stop();
- }
-
- mVerticalStrength = verticalStrength;
- mStopping = false;
- }
-
- private void start() {
- mUiHandler.post(this);
- mPreviousCallbackTime = 0;
- mStartTime = 0;
- }
-
- public void stop() {
- mStopping = true;
- }
-
- public void run() {
- if (mStopping) {
- mHorizontalStrength *= STOP_SLOWDOWN;
- mVerticalStrength *= STOP_SLOWDOWN;
- }
-
- if (mHorizontalStrength == 0 && mVerticalStrength == 0) {
- return;
- }
-
- boolean firstRun = mPreviousCallbackTime == 0;
- long curTime = SystemClock.elapsedRealtime();
- int panAmount = getPanAmount(mPreviousCallbackTime, curTime);
- mPreviousCallbackTime = curTime;
-
- if (firstRun) {
- mStartTime = curTime;
- mVelocity = mStartVelocity;
- } else {
- int panX = panAmount * mHorizontalStrength / 100;
- int panY = panAmount * mVerticalStrength / 100;
-
- if (mCallback != null) {
- mCallback.onPan(panX, panY);
- }
- }
-
- mUiHandler.postDelayed(this, RUN_DELAY);
- }
-
- 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;
- }
-
- }
-
- /**
- * Interface used to inform the client of zoom events that the user
- * triggers.
- */
- public interface OnZoomListener {
- /**
- * Called when the user begins dragging the thumb on the zoom ring.
- */
- void onBeginDrag();
-
- /**
- * Called when the user drags the thumb and passes a tick causing a
- * zoom.
- *
- * @param deltaZoomLevel The number of levels to be zoomed. Positive to
- * zoom in, negative to zoom out.
- * @param centerX The point about which to zoom. The zoom should pin
- * this point, leaving it at the same coordinate. This is
- * relative to the owner view's upper-left.
- * @param centerY The point about which to zoom. The zoom should pin
- * this point, leaving it at the same coordinate. This is
- * relative to the owner view's upper-left.
- * @param startAngle The angle where the user started dragging the thumb.
- * @param curAngle The current angle of the thumb.
- * @return Whether the owner was zoomed.
- */
- boolean onDragZoom(int deltaZoomLevel, int centerX, int centerY, float startAngle,
- float curAngle);
-
- /**
- * Called when the user releases the thumb.
- */
- void onEndDrag();
-
- /**
- * Called when the user zooms via some other mechanism, for example
- * arrow keys or a trackball.
- *
- * @param zoomIn Whether to zoom in (true) or out (false).
- * @param centerX See {@link #onDragZoom(int, int, int, float, float)}.
- * @param centerY See {@link #onDragZoom(int, int, int, float, float)}.
- */
- void onSimpleZoom(boolean zoomIn, int centerX, int centerY);
-
- /**
- * Called when the user begins moving the zoom ring in order to pan the
- * owner.
- */
- void onBeginPan();
-
- /**
- * Called when the owner should pan as a result of the user moving the zoom ring.
- *
- * @param deltaX The amount to pan horizontally.
- * @param deltaY The amount to pan vertically.
- * @return Whether the owner was panned.
- */
- boolean onPan(int deltaX, int deltaY);
-
- /**
- * Called when the user releases the zoom ring.
- */
- void onEndPan();
-
- /**
- * Called when the client should center the owner on the given point.
- *
- * @param x The x to center on, relative to the owner view's upper-left.
- * @param y The y to center on, relative to the owner view's upper-left.
- */
- void onCenter(int x, int y);
-
- /**
- * Called when the zoom ring's visibility changes.
- *
- * @param visible Whether the zoom ring is visible (true) or not (false).
- */
- void onVisibilityChanged(boolean visible);
- }
-}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 9030a3e..adec0a7 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -43,7 +43,7 @@ interface IInputMethodManager {
in ResultReceiver resultReceiver);
boolean hideSoftInput(in IInputMethodClient client, int flags,
in ResultReceiver resultReceiver);
- void windowGainedFocus(in IInputMethodClient client,
+ void windowGainedFocus(in IInputMethodClient client, in IBinder windowToken,
boolean viewHasFocus, boolean isTextEditor,
int softInputMode, boolean first, int windowFlags);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 6e5c4e0..18f2878 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -27,6 +27,7 @@ LOCAL_SRC_FILES:= \
android_database_SQLiteProgram.cpp \
android_database_SQLiteQuery.cpp \
android_database_SQLiteStatement.cpp \
+ android_emoji_EmojiFactory.cpp \
android_view_Display.cpp \
android_view_Surface.cpp \
android_view_ViewRoot.cpp \
@@ -132,6 +133,7 @@ LOCAL_C_INCLUDES += \
external/tremor/Tremor \
external/icu4c/i18n \
external/icu4c/common \
+ frameworks/opt/emoji
LOCAL_SHARED_LIBRARIES := \
libexpat \
@@ -156,12 +158,13 @@ LOCAL_SHARED_LIBRARIES := \
libicui18n \
libicudata \
libmedia \
- libwpa_client
+ libwpa_client \
+ libemoji
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_C_INCLUDES += \
external/dbus \
- external/bluez/libs/include
+ system/bluetooth/bluez-clean-headers
LOCAL_CFLAGS += -DHAVE_BLUETOOTH
LOCAL_SHARED_LIBRARIES += libbluedroid libdbus
endif
@@ -190,5 +193,4 @@ LOCAL_MODULE:= libandroid_runtime
include $(BUILD_SHARED_LIBRARY)
-
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 40dc2a1..28c602b 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -92,6 +92,7 @@ extern int register_android_util_EventLog(JNIEnv* env);
extern int register_android_util_Log(JNIEnv* env);
extern int register_android_content_StringBlock(JNIEnv* env);
extern int register_android_content_XmlBlock(JNIEnv* env);
+extern int register_android_emoji_EmojiFactory(JNIEnv* env);
extern int register_android_graphics_Canvas(JNIEnv* env);
extern int register_android_graphics_ColorFilter(JNIEnv* env);
extern int register_android_graphics_DrawFilter(JNIEnv* env);
@@ -1026,6 +1027,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
+ REG_JNI(register_android_emoji_EmojiFactory),
REG_JNI(register_android_security_Md5MessageDigest),
REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_KeyCharacterMap),
diff --git a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
index 7f87d80..bf23650 100755
--- a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
+++ b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
@@ -49,8 +49,6 @@
#ifdef HAVE_BLUETOOTH
#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/sco.h>
#endif
diff --git a/core/jni/android_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
new file mode 100644
index 0000000..59f63a8
--- /dev/null
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -0,0 +1,292 @@
+#include "SkTypes.h"
+#include "SkImageDecoder.h"
+
+#define LOG_TAG "DoCoMoEmojiFactory_jni"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "EmojiFactory.h"
+#include <nativehelper/JNIHelp.h>
+
+#include <dlfcn.h>
+// #include <pthread.h>
+
+namespace android {
+
+// Note: This class is originally developed so that libandroid_runtime does
+// not have to depend on libemoji which is optional library. However, we
+// cannot use this class, since current (2009-02-16) bionic libc does not allow
+// dlopen()-ing inside dlopen(), while not only this class but also libemoji
+// uses dlopen().
+class EmojiFactoryCaller {
+ public:
+ EmojiFactoryCaller();
+ virtual ~EmojiFactoryCaller();
+ EmojiFactory *TryCallGetImplementation(const char* name);
+ EmojiFactory *TryCallGetAvailableImplementation();
+ private:
+ void *m_handle;
+ EmojiFactory *(*m_get_implementation)(const char*);
+ EmojiFactory *(*m_get_available_implementation)();
+};
+
+EmojiFactoryCaller::EmojiFactoryCaller() {
+ m_handle = dlopen("libemoji.so", RTLD_LAZY | RTLD_LOCAL);
+ const char* error_str = dlerror();
+ if (error_str) {
+ LOGI("Failed to load libemoji.so: %s", error_str);
+ return;
+ }
+
+ m_get_implementation =
+ reinterpret_cast<EmojiFactory *(*)(const char*)>(
+ dlsym(m_handle, "GetImplementation"));
+ error_str = dlerror();
+ if (error_str) {
+ LOGE("Failed to get symbol of GetImplementation: %s", error_str);
+ dlclose(m_handle);
+ m_handle = NULL;
+ return;
+ }
+
+ m_get_available_implementation =
+ reinterpret_cast<EmojiFactory *(*)()>(
+ dlsym(m_handle,"GetAvailableImplementation"));
+ error_str = dlerror();
+ if (error_str) {
+ LOGE("Failed to get symbol of GetAvailableImplementation: %s", error_str);
+ dlclose(m_handle);
+ m_handle = NULL;
+ return;
+ }
+}
+
+EmojiFactoryCaller::~EmojiFactoryCaller() {
+ if (m_handle) {
+ dlclose(m_handle);
+ }
+}
+
+EmojiFactory *EmojiFactoryCaller::TryCallGetImplementation(
+ const char* name) {
+ if (NULL == m_handle) {
+ return NULL;
+ }
+ return m_get_implementation(name);
+}
+
+EmojiFactory *EmojiFactoryCaller::TryCallGetAvailableImplementation() {
+ if (NULL == m_handle) {
+ return NULL;
+ }
+ return m_get_available_implementation();
+}
+
+// Note: bionic libc's dlopen() does not allow recursive dlopen(). So currently
+// we cannot use EmojiFactoryCaller here.
+// static EmojiFactoryCaller* gCaller;
+// static pthread_once_t g_once = PTHREAD_ONCE_INIT;
+
+static jclass gString_class;
+
+static jclass gBitmap_class;
+static jmethodID gBitmap_constructorMethodID;
+
+static jclass gEmojiFactory_class;
+static jmethodID gEmojiFactory_constructorMethodID;
+
+// static void InitializeCaller() {
+// gCaller = new EmojiFactoryCaller();
+// }
+
+static jobject create_java_EmojiFactory(
+ JNIEnv* env, EmojiFactory* factory, jstring name) {
+ jobject obj = env->AllocObject(gEmojiFactory_class);
+ if (obj) {
+ env->CallVoidMethod(obj, gEmojiFactory_constructorMethodID,
+ (jint)factory, name);
+ if (env->ExceptionCheck() != 0) {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ obj = NULL;
+ }
+ }
+ return obj;
+}
+
+static jobject android_emoji_EmojiFactory_newInstance(
+ JNIEnv* env, jobject clazz, jstring name) {
+ // pthread_once(&g_once, InitializeCaller);
+
+ if (NULL == name) {
+ return NULL;
+ }
+
+ const jchar* jchars = env->GetStringChars(name, NULL);
+ jsize len = env->GetStringLength(name);
+ String8 str(String16(jchars, len));
+
+ // EmojiFactory *factory = gCaller->TryCallGetImplementation(str.string());
+ EmojiFactory *factory = EmojiFactory::GetImplementation(str.string());
+
+ env->ReleaseStringChars(name, jchars);
+
+ return create_java_EmojiFactory(env, factory, name);
+}
+
+static jobject android_emoji_EmojiFactory_newAvailableInstance(
+ JNIEnv* env, jobject clazz) {
+ // pthread_once(&g_once, InitializeCaller);
+
+ // EmojiFactory *factory = gCaller->TryCallGetAvailableImplementation();
+ EmojiFactory *factory = EmojiFactory::GetAvailableImplementation();
+ if (NULL == factory) {
+ return NULL;
+ }
+ String16 name_16(String8(factory->Name()));
+ jstring jname = env->NewString(name_16.string(), name_16.size());
+ if (NULL == jname) {
+ return NULL;
+ }
+
+ return create_java_EmojiFactory(env, factory, jname);
+}
+
+static jobject android_emoji_EmojiFactory_getBitmapFromAndroidPua(
+ JNIEnv* env, jobject clazz, jint nativeEmojiFactory, jint pua) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+
+ int size;
+ const char *bytes = factory->GetImageBinaryFromAndroidPua(pua, &size);
+ if (bytes == NULL) {
+ return NULL;
+ }
+
+ SkBitmap *bitmap = new SkBitmap;
+ if (!SkImageDecoder::DecodeMemory(bytes, size, bitmap)) {
+ LOGE("SkImageDecoder::DecodeMemory() failed.");
+ return NULL;
+ }
+
+ jobject obj = env->AllocObject(gBitmap_class);
+ if (obj) {
+ env->CallVoidMethod(obj, gBitmap_constructorMethodID,
+ reinterpret_cast<jint>(bitmap), false, NULL);
+ if (env->ExceptionCheck() != 0) {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ return NULL;
+ }
+ }
+
+ return obj;
+}
+
+static void android_emoji_EmojiFactory_destructor(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ delete factory;
+}
+
+static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory, jchar sjis) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetAndroidPuaFromVendorSpecificSjis(sjis);
+}
+
+static jint android_emoji_EmojiFactory_getVendorSpecificSjisFromAndroidPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint pua) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetVendorSpecificSjisFromAndroidPua(pua);
+}
+
+static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint vsu) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetAndroidPuaFromVendorSpecificPua(vsu);
+}
+
+static jint android_emoji_EmojiFactory_getVendorSpecificPuaFromAndroidPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint pua) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetVendorSpecificPuaFromAndroidPua(pua);
+}
+
+static jint android_emoji_EmojiFactory_getMaximumVendorSpecificPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetMaximumVendorSpecificPua();
+}
+
+static jint android_emoji_EmojiFactory_getMinimumVendorSpecificPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetMinimumVendorSpecificPua();
+}
+
+static jint android_emoji_EmojiFactory_getMaximumAndroidPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetMaximumAndroidPua();
+}
+
+static jint android_emoji_EmojiFactory_getMinimumAndroidPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetMinimumAndroidPua();
+}
+
+static JNINativeMethod gMethods[] = {
+ { "newInstance", "(Ljava/lang/String;)Landroid/emoji/EmojiFactory;",
+ (void*)android_emoji_EmojiFactory_newInstance},
+ { "newAvailableInstance", "()Landroid/emoji/EmojiFactory;",
+ (void*)android_emoji_EmojiFactory_newAvailableInstance},
+ { "nativeDestructor", "(I)V",
+ (void*)android_emoji_EmojiFactory_destructor},
+ { "nativeGetBitmapFromAndroidPua", "(II)Landroid/graphics/Bitmap;",
+ (void*)android_emoji_EmojiFactory_getBitmapFromAndroidPua},
+ { "nativeGetAndroidPuaFromVendorSpecificSjis", "(IC)I",
+ (void*)android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis},
+ { "nativeGetVendorSpecificSjisFromAndroidPua", "(II)I",
+ (void*)android_emoji_EmojiFactory_getVendorSpecificSjisFromAndroidPua},
+ { "nativeGetAndroidPuaFromVendorSpecificPua", "(II)I",
+ (void*)android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificPua},
+ { "nativeGetVendorSpecificPuaFromAndroidPua", "(II)I",
+ (void*)android_emoji_EmojiFactory_getVendorSpecificPuaFromAndroidPua},
+ { "nativeGetMaximumVendorSpecificPua", "(I)I",
+ (void*)android_emoji_EmojiFactory_getMaximumVendorSpecificPua},
+ { "nativeGetMinimumVendorSpecificPua", "(I)I",
+ (void*)android_emoji_EmojiFactory_getMinimumVendorSpecificPua},
+ { "nativeGetMaximumAndroidPua", "(I)I",
+ (void*)android_emoji_EmojiFactory_getMaximumAndroidPua},
+ { "nativeGetMinimumAndroidPua", "(I)I",
+ (void*)android_emoji_EmojiFactory_getMinimumAndroidPua}
+};
+
+static jclass make_globalref(JNIEnv* env, const char classname[])
+{
+ jclass c = env->FindClass(classname);
+ SkASSERT(c);
+ return (jclass)env->NewGlobalRef(c);
+}
+
+static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
+ const char fieldname[], const char type[])
+{
+ jfieldID id = env->GetFieldID(clazz, fieldname, type);
+ SkASSERT(id);
+ return id;
+}
+
+int register_android_emoji_EmojiFactory(JNIEnv* env) {
+ gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
+ gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
+ "(IZ[B)V");
+ gEmojiFactory_class = make_globalref(env, "android/emoji/EmojiFactory");
+ gEmojiFactory_constructorMethodID = env->GetMethodID(
+ gEmojiFactory_class, "<init>", "(ILjava/lang/String;)V");
+ return jniRegisterNativeMethods(env, "android/emoji/EmojiFactory",
+ gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index c98207a..fcab813 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -397,6 +397,16 @@ static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env,
return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
}
+static jboolean android_net_wifi_setBluetoothCoexistenceScanModeCommand(JNIEnv* env, jobject clazz, jboolean setCoexScanMode)
+{
+ char cmdstr[256];
+
+ int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER BTCOEXSCAN-%s", setCoexScanMode ? "START" : "STOP");
+ int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
+
+ return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
static jboolean android_net_wifi_saveConfigCommand(JNIEnv* env, jobject clazz)
{
// Make sure we never write out a value for AP_SCAN other than 1
@@ -503,6 +513,8 @@ static JNINativeMethod gWifiMethods[] = {
{ "getNumAllowedChannelsCommand", "()I", (void*) android_net_wifi_getNumAllowedChannelsCommand },
{ "setBluetoothCoexistenceModeCommand", "(I)Z",
(void*) android_net_wifi_setBluetoothCoexistenceModeCommand },
+ { "setBluetoothCoexistenceScanModeCommand", "(Z)Z",
+ (void*) android_net_wifi_setBluetoothCoexistenceScanModeCommand },
{ "getRssiCommand", "()I", (void*) android_net_wifi_getRssiCommand },
{ "getLinkSpeedCommand", "()I", (void*) android_net_wifi_getLinkSpeedCommand },
{ "getMacAddressCommand", "()Ljava/lang/String;", (void*) android_net_wifi_getMacAddressCommand },
diff --git a/core/jni/server/Android.mk b/core/jni/server/Android.mk
deleted file mode 100644
index 2f48edf..0000000
--- a/core/jni/server/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- com_android_server_AlarmManagerService.cpp \
- com_android_server_BatteryService.cpp \
- com_android_server_HardwareService.cpp \
- com_android_server_KeyInputQueue.cpp \
- com_android_server_SensorService.cpp \
- com_android_server_SystemServer.cpp \
- onload.cpp
-
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libhardware \
- libhardware_legacy \
- libnativehelper \
- libsystem_server \
- libutils \
- libui
-
-ifeq ($(TARGET_SIMULATOR),true)
-ifeq ($(TARGET_OS),linux)
-ifeq ($(TARGET_ARCH),x86)
-LOCAL_LDLIBS += -lpthread -ldl -lrt
-endif
-endif
-endif
-
-ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
- LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
-endif
-
-LOCAL_MODULE:= libandroid_servers
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/core/jni/server/com_android_server_AlarmManagerService.cpp b/core/jni/server/com_android_server_AlarmManagerService.cpp
deleted file mode 100644
index 1d66fb1..0000000
--- a/core/jni/server/com_android_server_AlarmManagerService.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/* //device/libs/android_runtime/android_server_AlarmManagerService.cpp
-**
-** Copyright 2006, 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.
-*/
-
-#define LOG_TAG "AlarmManagerService"
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/ioctl.h>
-#include <linux/android_alarm.h>
-#endif
-
-#define ONE_NANOSECOND 1000000000LL
-#define NANOSECONDS_TO_SECONDS(x) (x / ONE_NANOSECOND)
-#define SECONDS_TO_NANOSECONDS(x) (x * ONE_NANOSECOND)
-
-namespace android {
-
-static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest)
-{
-#if HAVE_ANDROID_OS
- struct timezone tz;
-
- tz.tz_minuteswest = minswest;
- tz.tz_dsttime = 0;
-
- int result = settimeofday(NULL, &tz);
- if (result < 0) {
- LOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
- return -1;
- } else {
- LOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
- }
-
- return 0;
-#else
- return -ENOSYS;
-#endif
-}
-
-static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj)
-{
-#if HAVE_ANDROID_OS
- return open("/dev/alarm", O_RDWR);
-#else
- return -1;
-#endif
-}
-
-static void android_server_AlarmManagerService_close(JNIEnv* env, jobject obj, jint fd)
-{
-#if HAVE_ANDROID_OS
- close(fd);
-#endif
-}
-
-static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong nanoseconds)
-{
-#if HAVE_ANDROID_OS
- struct timespec ts;
- ts.tv_sec = NANOSECONDS_TO_SECONDS(nanoseconds);
- ts.tv_nsec = nanoseconds - SECONDS_TO_NANOSECONDS(ts.tv_sec);
-
- int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);
- if (result < 0)
- {
- LOGE("Unable to set alarm to %lld: %s\n", nanoseconds, strerror(errno));
- }
-#endif
-}
-
-static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject obj, jint fd)
-{
-#if HAVE_ANDROID_OS
- int result = 0;
-
- do
- {
- result = ioctl(fd, ANDROID_ALARM_WAIT);
- } while (result < 0 && errno == EINTR);
-
- if (result < 0)
- {
- LOGE("Unable to wait on alarm: %s\n", strerror(errno));
- return 0;
- }
-
- return result;
-#endif
-}
-
-static JNINativeMethod sMethods[] = {
- /* name, signature, funcPtr */
- {"init", "()I", (void*)android_server_AlarmManagerService_init},
- {"close", "(I)V", (void*)android_server_AlarmManagerService_close},
- {"set", "(IIJ)V", (void*)android_server_AlarmManagerService_set},
- {"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm},
- {"setKernelTimezone", "(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
-};
-
-int register_android_server_AlarmManagerService(JNIEnv* env)
-{
- jclass clazz = env->FindClass("com/android/server/AlarmManagerService");
-
- if (clazz == NULL)
- {
- LOGE("Can't find com/android/server/AlarmManagerService");
- return -1;
- }
-
- return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
- sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/core/jni/server/com_android_server_BatteryService.cpp b/core/jni/server/com_android_server_BatteryService.cpp
deleted file mode 100644
index 6636a97..0000000
--- a/core/jni/server/com_android_server_BatteryService.cpp
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BatteryService"
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/ioctl.h>
-#endif
-
-namespace android {
-
-#define AC_ONLINE_PATH "/sys/class/power_supply/ac/online"
-#define USB_ONLINE_PATH "/sys/class/power_supply/usb/online"
-#define BATTERY_STATUS_PATH "/sys/class/power_supply/battery/status"
-#define BATTERY_HEALTH_PATH "/sys/class/power_supply/battery/health"
-#define BATTERY_PRESENT_PATH "/sys/class/power_supply/battery/present"
-#define BATTERY_CAPACITY_PATH "/sys/class/power_supply/battery/capacity"
-#define BATTERY_VOLTAGE_PATH "/sys/class/power_supply/battery/batt_vol"
-#define BATTERY_TEMPERATURE_PATH "/sys/class/power_supply/battery/batt_temp"
-#define BATTERY_TECHNOLOGY_PATH "/sys/class/power_supply/battery/technology"
-
-struct FieldIds {
- // members
- jfieldID mAcOnline;
- jfieldID mUsbOnline;
- jfieldID mBatteryStatus;
- jfieldID mBatteryHealth;
- jfieldID mBatteryPresent;
- jfieldID mBatteryLevel;
- jfieldID mBatteryVoltage;
- jfieldID mBatteryTemperature;
- jfieldID mBatteryTechnology;
-};
-static FieldIds gFieldIds;
-
-struct BatteryManagerConstants {
- jint statusUnknown;
- jint statusCharging;
- jint statusDischarging;
- jint statusNotCharging;
- jint statusFull;
- jint healthUnknown;
- jint healthGood;
- jint healthOverheat;
- jint healthDead;
- jint healthOverVoltage;
- jint healthUnspecifiedFailure;
-};
-static BatteryManagerConstants gConstants;
-
-static jint getBatteryStatus(const char* status)
-{
- switch (status[0]) {
- case 'C': return gConstants.statusCharging; // Charging
- case 'D': return gConstants.statusDischarging; // Discharging
- case 'F': return gConstants.statusFull; // Not charging
- case 'N': return gConstants.statusNotCharging; // Full
- case 'U': return gConstants.statusUnknown; // Unknown
-
- default: {
- LOGW("Unknown battery status '%s'", status);
- return gConstants.statusUnknown;
- }
- }
-}
-
-static jint getBatteryHealth(const char* status)
-{
- switch (status[0]) {
- case 'D': return gConstants.healthDead; // Dead
- case 'G': return gConstants.healthGood; // Good
- case 'O': {
- if (strcmp(status, "Overheat") == 0) {
- return gConstants.healthOverheat;
- } else if (strcmp(status, "Over voltage") == 0) {
- return gConstants.healthOverVoltage;
- }
- LOGW("Unknown battery health[1] '%s'", status);
- return gConstants.healthUnknown;
- }
-
- case 'U': {
- if (strcmp(status, "Unspecified failure") == 0) {
- return gConstants.healthUnspecifiedFailure;
- } else if (strcmp(status, "Unknown") == 0) {
- return gConstants.healthUnknown;
- }
- // fall through
- }
-
- default: {
- LOGW("Unknown battery health[2] '%s'", status);
- return gConstants.healthUnknown;
- }
- }
-}
-
-static int readFromFile(const char* path, char* buf, size_t size)
-{
- int fd = open(path, O_RDONLY, 0);
- if (fd == -1) {
- LOGE("Could not open '%s'", path);
- return -1;
- }
-
- size_t count = read(fd, buf, size);
- if (count > 0) {
- count = (count < size) ? count : size - 1;
- while (count > 0 && buf[count-1] == '\n') count--;
- buf[count] = '\0';
- } else {
- buf[0] = '\0';
- }
-
- close(fd);
- return count;
-}
-
-static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
-{
- const int SIZE = 16;
- char buf[SIZE];
-
- jboolean value = false;
- if (readFromFile(path, buf, SIZE) > 0) {
- if (buf[0] == '1') {
- value = true;
- }
- }
- env->SetBooleanField(obj, fieldID, value);
-}
-
-static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
-{
- const int SIZE = 128;
- char buf[SIZE];
-
- jint value = 0;
- if (readFromFile(path, buf, SIZE) > 0) {
- value = atoi(buf);
- }
- env->SetIntField(obj, fieldID, value);
-}
-
-static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
-{
- setBooleanField(env, obj, AC_ONLINE_PATH, gFieldIds.mAcOnline);
- setBooleanField(env, obj, USB_ONLINE_PATH, gFieldIds.mUsbOnline);
- setBooleanField(env, obj, BATTERY_PRESENT_PATH, gFieldIds.mBatteryPresent);
-
- setIntField(env, obj, BATTERY_CAPACITY_PATH, gFieldIds.mBatteryLevel);
- setIntField(env, obj, BATTERY_VOLTAGE_PATH, gFieldIds.mBatteryVoltage);
- setIntField(env, obj, BATTERY_TEMPERATURE_PATH, gFieldIds.mBatteryTemperature);
-
- const int SIZE = 128;
- char buf[SIZE];
-
- if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0)
- env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
-
- if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0)
- env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));
-
- if (readFromFile(BATTERY_TECHNOLOGY_PATH, buf, SIZE) > 0)
- env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
-}
-
-static JNINativeMethod sMethods[] = {
- /* name, signature, funcPtr */
- {"native_update", "()V", (void*)android_server_BatteryService_update},
-};
-
-int register_android_server_BatteryService(JNIEnv* env)
-{
- jclass clazz = env->FindClass("com/android/server/BatteryService");
-
- if (clazz == NULL) {
- LOGE("Can't find com/android/server/BatteryService");
- return -1;
- }
-
- gFieldIds.mAcOnline = env->GetFieldID(clazz, "mAcOnline", "Z");
- gFieldIds.mUsbOnline = env->GetFieldID(clazz, "mUsbOnline", "Z");
- gFieldIds.mBatteryStatus = env->GetFieldID(clazz, "mBatteryStatus", "I");
- gFieldIds.mBatteryHealth = env->GetFieldID(clazz, "mBatteryHealth", "I");
- gFieldIds.mBatteryPresent = env->GetFieldID(clazz, "mBatteryPresent", "Z");
- gFieldIds.mBatteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I");
- gFieldIds.mBatteryTechnology = env->GetFieldID(clazz, "mBatteryTechnology", "Ljava/lang/String;");
- gFieldIds.mBatteryVoltage = env->GetFieldID(clazz, "mBatteryVoltage", "I");
- gFieldIds.mBatteryTemperature = env->GetFieldID(clazz, "mBatteryTemperature", "I");
-
- LOG_FATAL_IF(gFieldIds.mAcOnline == NULL, "Unable to find BatteryService.AC_ONLINE_PATH");
- LOG_FATAL_IF(gFieldIds.mUsbOnline == NULL, "Unable to find BatteryService.USB_ONLINE_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryStatus == NULL, "Unable to find BatteryService.BATTERY_STATUS_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryHealth == NULL, "Unable to find BatteryService.BATTERY_HEALTH_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryPresent == NULL, "Unable to find BatteryService.BATTERY_PRESENT_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryLevel == NULL, "Unable to find BatteryService.BATTERY_CAPACITY_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryVoltage == NULL, "Unable to find BatteryService.BATTERY_VOLTAGE_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryTemperature == NULL, "Unable to find BatteryService.BATTERY_TEMPERATURE_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryTechnology == NULL, "Unable to find BatteryService.BATTERY_TECHNOLOGY_PATH");
-
- clazz = env->FindClass("android/os/BatteryManager");
-
- if (clazz == NULL) {
- LOGE("Can't find android/os/BatteryManager");
- return -1;
- }
-
- gConstants.statusUnknown = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_STATUS_UNKNOWN", "I"));
-
- gConstants.statusCharging = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_STATUS_CHARGING", "I"));
-
- gConstants.statusDischarging = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_STATUS_DISCHARGING", "I"));
-
- gConstants.statusNotCharging = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_STATUS_NOT_CHARGING", "I"));
-
- gConstants.statusFull = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_STATUS_FULL", "I"));
-
- gConstants.healthUnknown = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNKNOWN", "I"));
-
- gConstants.healthGood = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_GOOD", "I"));
-
- gConstants.healthOverheat = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVERHEAT", "I"));
-
- gConstants.healthDead = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_DEAD", "I"));
-
- gConstants.healthOverVoltage = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVER_VOLTAGE", "I"));
-
- gConstants.healthUnspecifiedFailure = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNSPECIFIED_FAILURE", "I"));
-
- return jniRegisterNativeMethods(env, "com/android/server/BatteryService", sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/core/jni/server/com_android_server_HardwareService.cpp b/core/jni/server/com_android_server_HardwareService.cpp
deleted file mode 100644
index ac36348..0000000
--- a/core/jni/server/com_android_server_HardwareService.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/* //device/libs/android_runtime/android_os_Vibrator.cpp
-**
-** Copyright 2006, 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.
-*/
-
-#define LOG_TAG "Vibrator"
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include <stdio.h>
-#include "android_runtime/AndroidRuntime.h"
-#include <utils/misc.h>
-#include <utils/Log.h>
-#include <hardware_legacy/vibrator.h>
-
-namespace android
-{
-
-static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms)
-{
- // LOGI("vibratorOn\n");
- vibrator_on(timeout_ms);
-}
-
-static void vibratorOff(JNIEnv *env, jobject clazz)
-{
- // LOGI("vibratorOff\n");
- vibrator_off();
-}
-
-static JNINativeMethod method_table[] = {
- { "vibratorOn", "(J)V", (void*)vibratorOn },
- { "vibratorOff", "()V", (void*)vibratorOff }
-};
-
-int register_android_os_Vibrator(JNIEnv *env)
-{
- return jniRegisterNativeMethods(env, "com/android/server/HardwareService",
- method_table, NELEM(method_table));
-}
-
-};
diff --git a/core/jni/server/com_android_server_KeyInputQueue.cpp b/core/jni/server/com_android_server_KeyInputQueue.cpp
deleted file mode 100644
index 63830d5..0000000
--- a/core/jni/server/com_android_server_KeyInputQueue.cpp
+++ /dev/null
@@ -1,320 +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.
- */
-
-#define LOG_TAG "Input"
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include <utils/misc.h>
-#include <utils/Log.h>
-
-#include <ui/EventHub.h>
-#include <utils/threads.h>
-
-#include <stdio.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static struct input_offsets_t
-{
- jfieldID mMinValue;
- jfieldID mMaxValue;
- jfieldID mFlat;
- jfieldID mFuzz;
-
- jfieldID mDeviceId;
- jfieldID mType;
- jfieldID mScancode;
- jfieldID mKeycode;
- jfieldID mFlags;
- jfieldID mValue;
- jfieldID mWhen;
-} gInputOffsets;
-
-// ----------------------------------------------------------------------------
-
-static Mutex gLock;
-static sp<EventHub> gHub;
-
-static jboolean
-android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
- jobject event)
-{
- gLock.lock();
- sp<EventHub> hub = gHub;
- if (hub == NULL) {
- hub = new EventHub;
- gHub = hub;
- }
- gLock.unlock();
-
- int32_t deviceId;
- int32_t type;
- int32_t scancode, keycode;
- uint32_t flags;
- int32_t value;
- nsecs_t when;
- bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
- &flags, &value, &when);
-
- env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
- env->SetIntField(event, gInputOffsets.mType, (jint)type);
- env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
- env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
- env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
- env->SetIntField(event, gInputOffsets.mValue, value);
- env->SetLongField(event, gInputOffsets.mWhen,
- (jlong)(nanoseconds_to_milliseconds(when)));
-
- return res;
-}
-
-static jint
-android_server_KeyInputQueue_getDeviceClasses(JNIEnv* env, jobject clazz,
- jint deviceId)
-{
- jint classes = 0;
- gLock.lock();
- if (gHub != NULL) classes = gHub->getDeviceClasses(deviceId);
- gLock.unlock();
- return classes;
-}
-
-static jstring
-android_server_KeyInputQueue_getDeviceName(JNIEnv* env, jobject clazz,
- jint deviceId)
-{
- String8 name;
- gLock.lock();
- if (gHub != NULL) name = gHub->getDeviceName(deviceId);
- gLock.unlock();
-
- if (name.size() > 0) {
- return env->NewStringUTF(name.string());
- }
- return NULL;
-}
-
-static jboolean
-android_server_KeyInputQueue_getAbsoluteInfo(JNIEnv* env, jobject clazz,
- jint deviceId, jint axis,
- jobject info)
-{
- int32_t minValue, maxValue, flat, fuzz;
- int res = -1;
- gLock.lock();
- if (gHub != NULL) {
- res = gHub->getAbsoluteInfo(deviceId, axis,
- &minValue, &maxValue, &flat, &fuzz);
- }
- gLock.unlock();
-
- if (res < 0) return JNI_FALSE;
-
- env->SetIntField(info, gInputOffsets.mMinValue, (jint)minValue);
- env->SetIntField(info, gInputOffsets.mMaxValue, (jint)maxValue);
- env->SetIntField(info, gInputOffsets.mFlat, (jint)flat);
- env->SetIntField(info, gInputOffsets.mFuzz, (jint)fuzz);
- return JNI_TRUE;
-}
-
-static jint
-android_server_KeyInputQueue_getSwitchState(JNIEnv* env, jobject clazz,
- jint sw)
-{
- jint st = -1;
- gLock.lock();
- if (gHub != NULL) st = gHub->getSwitchState(sw);
- gLock.unlock();
-
- return st;
-}
-
-static jint
-android_server_KeyInputQueue_getSwitchStateDevice(JNIEnv* env, jobject clazz,
- jint deviceId, jint sw)
-{
- jint st = -1;
- gLock.lock();
- if (gHub != NULL) st = gHub->getSwitchState(deviceId, sw);
- gLock.unlock();
-
- return st;
-}
-
-static jint
-android_server_KeyInputQueue_getScancodeState(JNIEnv* env, jobject clazz,
- jint sw)
-{
- jint st = -1;
- gLock.lock();
- if (gHub != NULL) st = gHub->getScancodeState(sw);
- gLock.unlock();
-
- return st;
-}
-
-static jint
-android_server_KeyInputQueue_getScancodeStateDevice(JNIEnv* env, jobject clazz,
- jint deviceId, jint sw)
-{
- jint st = -1;
- gLock.lock();
- if (gHub != NULL) st = gHub->getScancodeState(deviceId, sw);
- gLock.unlock();
-
- return st;
-}
-
-static jint
-android_server_KeyInputQueue_getKeycodeState(JNIEnv* env, jobject clazz,
- jint sw)
-{
- jint st = -1;
- gLock.lock();
- if (gHub != NULL) st = gHub->getKeycodeState(sw);
- gLock.unlock();
-
- return st;
-}
-
-static jint
-android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz,
- jint deviceId, jint sw)
-{
- jint st = -1;
- gLock.lock();
- if (gHub != NULL) st = gHub->getKeycodeState(deviceId, sw);
- gLock.unlock();
-
- return st;
-}
-
-static jboolean
-android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz,
- jintArray keyCodes, jbooleanArray outFlags)
-{
- jboolean ret = JNI_FALSE;
-
- int32_t* codes = env->GetIntArrayElements(keyCodes, NULL);
- uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL);
- size_t numCodes = env->GetArrayLength(keyCodes);
- if (numCodes == env->GetArrayLength(outFlags)) {
- gLock.lock();
- if (gHub != NULL) ret = gHub->hasKeys(numCodes, codes, flags);
- gLock.unlock();
- }
-
- env->ReleaseBooleanArrayElements(outFlags, flags, 0);
- env->ReleaseIntArrayElements(keyCodes, codes, 0);
- return ret;
-}
-
-// ----------------------------------------------------------------------------
-
-/*
- * JNI registration.
- */
-static JNINativeMethod gInputMethods[] = {
- /* name, signature, funcPtr */
- { "readEvent", "(Landroid/view/RawInputEvent;)Z",
- (void*) android_server_KeyInputQueue_readEvent },
- { "getDeviceClasses", "(I)I",
- (void*) android_server_KeyInputQueue_getDeviceClasses },
- { "getDeviceName", "(I)Ljava/lang/String;",
- (void*) android_server_KeyInputQueue_getDeviceName },
- { "getAbsoluteInfo", "(IILcom/android/server/InputDevice$AbsoluteInfo;)Z",
- (void*) android_server_KeyInputQueue_getAbsoluteInfo },
- { "getSwitchState", "(I)I",
- (void*) android_server_KeyInputQueue_getSwitchState },
- { "getSwitchState", "(II)I",
- (void*) android_server_KeyInputQueue_getSwitchStateDevice },
- { "getScancodeState", "(I)I",
- (void*) android_server_KeyInputQueue_getScancodeState },
- { "getScancodeState", "(II)I",
- (void*) android_server_KeyInputQueue_getScancodeStateDevice },
- { "getKeycodeState", "(I)I",
- (void*) android_server_KeyInputQueue_getKeycodeState },
- { "getKeycodeState", "(II)I",
- (void*) android_server_KeyInputQueue_getKeycodeStateDevice },
- { "hasKeys", "([I[Z)Z",
- (void*) android_server_KeyInputQueue_hasKeys },
-};
-
-int register_android_server_KeyInputQueue(JNIEnv* env)
-{
- jclass input = env->FindClass("com/android/server/KeyInputQueue");
- LOG_FATAL_IF(input == NULL, "Unable to find class com/android/server/KeyInputQueue");
- int res = jniRegisterNativeMethods(env, "com/android/server/KeyInputQueue",
- gInputMethods, NELEM(gInputMethods));
-
- jclass absoluteInfo = env->FindClass("com/android/server/InputDevice$AbsoluteInfo");
- LOG_FATAL_IF(absoluteInfo == NULL, "Unable to find class com/android/server/InputDevice$AbsoluteInfo");
-
- gInputOffsets.mMinValue
- = env->GetFieldID(absoluteInfo, "minValue", "I");
- LOG_FATAL_IF(gInputOffsets.mMinValue == NULL, "Unable to find InputDevice.AbsoluteInfo.minValue");
-
- gInputOffsets.mMaxValue
- = env->GetFieldID(absoluteInfo, "maxValue", "I");
- LOG_FATAL_IF(gInputOffsets.mMaxValue == NULL, "Unable to find InputDevice.AbsoluteInfo.maxValue");
-
- gInputOffsets.mFlat
- = env->GetFieldID(absoluteInfo, "flat", "I");
- LOG_FATAL_IF(gInputOffsets.mFlat == NULL, "Unable to find InputDevice.AbsoluteInfo.flat");
-
- gInputOffsets.mFuzz
- = env->GetFieldID(absoluteInfo, "fuzz", "I");
- LOG_FATAL_IF(gInputOffsets.mFuzz == NULL, "Unable to find InputDevice.AbsoluteInfo.fuzz");
-
- jclass inputEvent = env->FindClass("android/view/RawInputEvent");
- LOG_FATAL_IF(inputEvent == NULL, "Unable to find class android/view/RawInputEvent");
-
- gInputOffsets.mDeviceId
- = env->GetFieldID(inputEvent, "deviceId", "I");
- LOG_FATAL_IF(gInputOffsets.mDeviceId == NULL, "Unable to find RawInputEvent.deviceId");
-
- gInputOffsets.mType
- = env->GetFieldID(inputEvent, "type", "I");
- LOG_FATAL_IF(gInputOffsets.mType == NULL, "Unable to find RawInputEvent.type");
-
- gInputOffsets.mScancode
- = env->GetFieldID(inputEvent, "scancode", "I");
- LOG_FATAL_IF(gInputOffsets.mScancode == NULL, "Unable to find RawInputEvent.scancode");
-
- gInputOffsets.mKeycode
- = env->GetFieldID(inputEvent, "keycode", "I");
- LOG_FATAL_IF(gInputOffsets.mKeycode == NULL, "Unable to find RawInputEvent.keycode");
-
- gInputOffsets.mFlags
- = env->GetFieldID(inputEvent, "flags", "I");
- LOG_FATAL_IF(gInputOffsets.mFlags == NULL, "Unable to find RawInputEvent.flags");
-
- gInputOffsets.mValue
- = env->GetFieldID(inputEvent, "value", "I");
- LOG_FATAL_IF(gInputOffsets.mValue == NULL, "Unable to find RawInputEvent.value");
-
- gInputOffsets.mWhen
- = env->GetFieldID(inputEvent, "when", "J");
- LOG_FATAL_IF(gInputOffsets.mWhen == NULL, "Unable to find RawInputEvent.when");
-
- return res;
-}
-
-}; // namespace android
-
diff --git a/core/jni/server/com_android_server_SensorService.cpp b/core/jni/server/com_android_server_SensorService.cpp
deleted file mode 100644
index 695a8a3..0000000
--- a/core/jni/server/com_android_server_SensorService.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#define LOG_TAG "Sensors"
-
-#include <hardware/sensors.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-
-namespace android {
-
-static struct file_descriptor_offsets_t
-{
- jclass mClass;
- jmethodID mConstructor;
- jfieldID mDescriptor;
-} gFileDescriptorOffsets;
-
-static struct parcel_file_descriptor_offsets_t
-{
- jclass mClass;
- jmethodID mConstructor;
-} gParcelFileDescriptorOffsets;
-
-/*
- * The method below are not thread-safe and not intended to be
- */
-
-static sensors_control_device_t* sSensorDevice = 0;
-
-static jint
-android_init(JNIEnv *env, jclass clazz)
-{
- sensors_module_t* module;
- if (hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {
- if (sensors_control_open(&module->common, &sSensorDevice) == 0) {
- const struct sensor_t* list;
- int count = module->get_sensors_list(module, &list);
- return count;
- }
- }
- return 0;
-}
-
-static jobject
-android_open(JNIEnv *env, jclass clazz)
-{
- int fd = sSensorDevice->open_data_source(sSensorDevice);
- // new FileDescriptor()
- jobject filedescriptor = env->NewObject(
- gFileDescriptorOffsets.mClass,
- gFileDescriptorOffsets.mConstructor);
-
- if (filedescriptor != NULL) {
- env->SetIntField(filedescriptor, gFileDescriptorOffsets.mDescriptor, fd);
- // new ParcelFileDescriptor()
- return env->NewObject(gParcelFileDescriptorOffsets.mClass,
- gParcelFileDescriptorOffsets.mConstructor,
- filedescriptor);
- }
- close(fd);
- return NULL;
-}
-
-static jboolean
-android_activate(JNIEnv *env, jclass clazz, jint sensor, jboolean activate)
-{
- int active = sSensorDevice->activate(sSensorDevice, sensor, activate);
- return (active<0) ? false : true;
-}
-
-static jint
-android_set_delay(JNIEnv *env, jclass clazz, jint ms)
-{
- return sSensorDevice->set_delay(sSensorDevice, ms);
-}
-
-static jint
-android_data_wake(JNIEnv *env, jclass clazz)
-{
- int res = sSensorDevice->wake(sSensorDevice);
- return res;
-}
-
-
-static JNINativeMethod gMethods[] = {
- {"_sensors_control_init", "()I", (void*) android_init },
- {"_sensors_control_open", "()Landroid/os/ParcelFileDescriptor;", (void*) android_open },
- {"_sensors_control_activate", "(IZ)Z", (void*) android_activate },
- {"_sensors_control_wake", "()I", (void*) android_data_wake },
- {"_sensors_control_set_delay","(I)I", (void*) android_set_delay },
-};
-
-int register_android_server_SensorService(JNIEnv *env)
-{
- jclass clazz;
-
- clazz = env->FindClass("java/io/FileDescriptor");
- gFileDescriptorOffsets.mClass = (jclass)env->NewGlobalRef(clazz);
- gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
- gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
-
- clazz = env->FindClass("android/os/ParcelFileDescriptor");
- gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
- gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
-
- return jniRegisterNativeMethods(env, "com/android/server/SensorService",
- gMethods, NELEM(gMethods));
-}
-
-}; // namespace android
diff --git a/core/jni/server/com_android_server_SystemServer.cpp b/core/jni/server/com_android_server_SystemServer.cpp
deleted file mode 100644
index ae29405..0000000
--- a/core/jni/server/com_android_server_SystemServer.cpp
+++ /dev/null
@@ -1,47 +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.
- */
-#include <utils/Log.h>
-#include <utils/misc.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-
-namespace android {
-
-extern "C" int system_init();
-
-static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
-{
- system_init();
-}
-
-/*
- * JNI registration.
- */
-static JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
-};
-
-int register_android_server_SystemServer(JNIEnv* env)
-{
- return jniRegisterNativeMethods(env, "com/android/server/SystemServer",
- gMethods, NELEM(gMethods));
-}
-
-}; // namespace android
-
-
diff --git a/core/jni/server/onload.cpp b/core/jni/server/onload.cpp
deleted file mode 100644
index 3d68cfb..0000000
--- a/core/jni/server/onload.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "JNIHelp.h"
-#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-
-namespace android {
-int register_android_server_AlarmManagerService(JNIEnv* env);
-int register_android_server_BatteryService(JNIEnv* env);
-int register_android_server_KeyInputQueue(JNIEnv* env);
-int register_android_os_Vibrator(JNIEnv* env);
-int register_android_server_SensorService(JNIEnv* env);
-int register_android_server_SystemServer(JNIEnv* env);
-};
-
-using namespace android;
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
-{
- JNIEnv* env = NULL;
- jint result = -1;
-
- if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- LOGE("GetEnv failed!");
- return result;
- }
- LOG_ASSERT(env, "Could not retrieve the env!");
-
- register_android_server_KeyInputQueue(env);
- register_android_os_Vibrator(env);
- register_android_server_AlarmManagerService(env);
- register_android_server_BatteryService(env);
- register_android_server_SensorService(env);
- register_android_server_SystemServer(env);
-
- return JNI_VERSION_1_4;
-}
diff --git a/core/res/Android.mk b/core/res/Android.mk
index 5fca5d0..cb5524a 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -24,7 +24,7 @@ LOCAL_CERTIFICATE := platform
# since these resources will be used by many apps.
LOCAL_AAPT_FLAGS := -x
-LOCAL_MODULE_TAGS := user development
+LOCAL_MODULE_TAGS := user
# Install this alongside the libraries.
LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)
diff --git a/core/res/res/anim/zoom_ring_enter.xml b/core/res/res/anim/zoom_ring_enter.xml
deleted file mode 100644
index 13d89b2..0000000
--- a/core/res/res/anim/zoom_ring_enter.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/anim/fade_in.xml
-**
-** Copyright 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@anim/decelerate_interpolator">
- <scale android:fromXScale="0.75" android:toXScale="1.0"
- android:fromYScale="0.75" android:toYScale="1.0"
- android:pivotX="50%" android:pivotY="50%"
- android:duration="75" />
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="75" />
-</set>
diff --git a/core/res/res/anim/zoom_ring_exit.xml b/core/res/res/anim/zoom_ring_exit.xml
deleted file mode 100644
index 177a4c3..0000000
--- a/core/res/res/anim/zoom_ring_exit.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/anim/fade_out.xml
-**
-** Copyright 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.
-*/
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@anim/accelerate_interpolator">
- <scale android:fromXScale="1.0" android:toXScale="0.75"
- android:fromYScale="1.0" android:toYScale="0.75"
- android:pivotX="50%" android:pivotY="50%"
- android:duration="75" />
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:duration="75"/>
-</set>
diff --git a/core/res/res/drawable-land/statusbar_background.png b/core/res/res/drawable-land/statusbar_background.png
index 8ecc24c..bafa5c5 100644
--- a/core/res/res/drawable-land/statusbar_background.png
+++ b/core/res/res/drawable-land/statusbar_background.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle.xml b/core/res/res/drawable/btn_circle.xml
new file mode 100644
index 0000000..9208010
--- /dev/null
+++ b/core/res/res/drawable/btn_circle.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_window_focused="false" android:state_enabled="true"
+ android:drawable="@drawable/btn_circle_normal" />
+ <item android:state_window_focused="false" android:state_enabled="false"
+ android:drawable="@drawable/btn_circle_disable" />
+ <item android:state_pressed="true"
+ android:drawable="@drawable/btn_circle_pressed" />
+ <item android:state_focused="true" android:state_enabled="true"
+ android:drawable="@drawable/btn_circle_selected" />
+ <item android:state_enabled="true"
+ android:drawable="@drawable/btn_circle_normal" />
+ <item android:state_focused="true"
+ android:drawable="@drawable/btn_circle_disable_focused" />
+ <item
+ android:drawable="@drawable/btn_circle_disable" />
+</selector>
diff --git a/core/res/res/drawable/btn_circle_disable.png b/core/res/res/drawable/btn_circle_disable.png
new file mode 100644
index 0000000..33b74a6
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_disable_focused.png b/core/res/res/drawable/btn_circle_disable_focused.png
new file mode 100644
index 0000000..005ad8d
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_longpress.png b/core/res/res/drawable/btn_circle_longpress.png
new file mode 100644
index 0000000..f27d411
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_longpress.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_normal.png b/core/res/res/drawable/btn_circle_normal.png
new file mode 100644
index 0000000..fc5af1c
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_pressed.png b/core/res/res/drawable/btn_circle_pressed.png
new file mode 100644
index 0000000..8f40afd
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_selected.png b/core/res/res/drawable/btn_circle_selected.png
new file mode 100644
index 0000000..c74fac2
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_selected.png
Binary files differ
diff --git a/core/res/res/drawable/extract_edit_text.xml b/core/res/res/drawable/extract_edit_text.xml
index 9c6c4ba..c7f66f6 100644
--- a/core/res/res/drawable/extract_edit_text.xml
+++ b/core/res/res/drawable/extract_edit_text.xml
@@ -15,7 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true" android:drawable="@drawable/keyboard_textfield_pressed" />
<item android:state_focused="true" android:drawable="@drawable/keyboard_textfield_selected" />
<item android:drawable="@drawable/textfield_disabled" />
</selector>
diff --git a/core/res/res/drawable/zoom_ring_thumb_plus_arrow_rotatable.xml b/core/res/res/drawable/ic_btn_round_more.xml
index b77eaa4..82b7593 100644
--- a/core/res/res/drawable/zoom_ring_thumb_plus_arrow_rotatable.xml
+++ b/core/res/res/drawable/ic_btn_round_more.xml
@@ -14,9 +14,9 @@
limitations under the License.
-->
-<rotate xmlns:android="http://schemas.android.com/apk/res/android"
- android:pivotX="50%"
- android:pivotY="50%"
- android:fromDegrees="0"
- android:toDegrees="360"
- android:drawable="@drawable/zoom_ring_thumb_plus_arrow" />
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:drawable="@drawable/ic_btn_round_more_disabled" />
+ <item
+ android:drawable="@drawable/ic_btn_round_more_normal" />
+</selector>
diff --git a/core/res/res/drawable/ic_btn_round_more_disabled.png b/core/res/res/drawable/ic_btn_round_more_disabled.png
new file mode 100644
index 0000000..1ab98c9
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_round_more_disabled.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_round_more_normal.png b/core/res/res/drawable/ic_btn_round_more_normal.png
new file mode 100644
index 0000000..ebdc55c
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_round_more_normal.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_textfield_pressed.9.png b/core/res/res/drawable/keyboard_textfield_pressed.9.png
deleted file mode 100644
index f4e3f10..0000000
--- a/core/res/res/drawable/keyboard_textfield_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_phone_call.png b/core/res/res/drawable/stat_sys_phone_call.png
index ad53693..c44d062 100644
--- a/core/res/res/drawable/stat_sys_phone_call.png
+++ b/core/res/res/drawable/stat_sys_phone_call.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_phone_call_bluetooth.png b/core/res/res/drawable/stat_sys_phone_call_bluetooth.png
new file mode 100644
index 0000000..7abfd19
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_phone_call_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable/statusbar_background.png b/core/res/res/drawable/statusbar_background.png
index 945ad92..25a2344 100644
--- a/core/res/res/drawable/statusbar_background.png
+++ b/core/res/res/drawable/statusbar_background.png
Binary files differ
diff --git a/core/res/res/drawable/zoom_ring_arrows.png b/core/res/res/drawable/zoom_ring_arrows.png
deleted file mode 100644
index e443de7..0000000
--- a/core/res/res/drawable/zoom_ring_arrows.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/zoom_ring_overview_tab.9.png b/core/res/res/drawable/zoom_ring_overview_tab.9.png
deleted file mode 100644
index d2658d8..0000000
--- a/core/res/res/drawable/zoom_ring_overview_tab.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/zoom_ring_thumb.png b/core/res/res/drawable/zoom_ring_thumb.png
deleted file mode 100644
index 1002724..0000000
--- a/core/res/res/drawable/zoom_ring_thumb.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/zoom_ring_thumb_minus.png b/core/res/res/drawable/zoom_ring_thumb_minus.png
deleted file mode 100644
index faed674..0000000
--- a/core/res/res/drawable/zoom_ring_thumb_minus.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/zoom_ring_thumb_minus_arrow.png b/core/res/res/drawable/zoom_ring_thumb_minus_arrow.png
deleted file mode 100644
index abe1b8a..0000000
--- a/core/res/res/drawable/zoom_ring_thumb_minus_arrow.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/zoom_ring_thumb_minus_arrow_rotatable.xml b/core/res/res/drawable/zoom_ring_thumb_minus_arrow_rotatable.xml
deleted file mode 100644
index f2d495b..0000000
--- a/core/res/res/drawable/zoom_ring_thumb_minus_arrow_rotatable.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<rotate xmlns:android="http://schemas.android.com/apk/res/android"
- android:pivotX="50%"
- android:pivotY="50%"
- android:fromDegrees="0"
- android:toDegrees="360"
- android:drawable="@drawable/zoom_ring_thumb_minus_arrow" />
diff --git a/core/res/res/drawable/zoom_ring_thumb_plus.png b/core/res/res/drawable/zoom_ring_thumb_plus.png
deleted file mode 100644
index ba7aff2..0000000
--- a/core/res/res/drawable/zoom_ring_thumb_plus.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/zoom_ring_thumb_plus_arrow.png b/core/res/res/drawable/zoom_ring_thumb_plus_arrow.png
deleted file mode 100644
index d01ccb4..0000000
--- a/core/res/res/drawable/zoom_ring_thumb_plus_arrow.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/zoom_ring_track.png b/core/res/res/drawable/zoom_ring_track.png
deleted file mode 100644
index 1d5a44c..0000000
--- a/core/res/res/drawable/zoom_ring_track.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/zoom_ring_track_absolute.png b/core/res/res/drawable/zoom_ring_track_absolute.png
deleted file mode 100644
index 2b87699..0000000
--- a/core/res/res/drawable/zoom_ring_track_absolute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/zoom_ring_trail.xml b/core/res/res/drawable/zoom_ring_trail.xml
deleted file mode 100644
index 08931ac..0000000
--- a/core/res/res/drawable/zoom_ring_trail.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<rotate xmlns:android="http://schemas.android.com/apk/res/android"
- android:pivotX="50%"
- android:pivotY="50%"
- android:fromDegrees="0"
- android:toDegrees="360">
-
- <shape
- android:shape="ring"
- android:innerRadius="60dip"
- android:thickness="14dip"
- android:useLevel="true">
-
- <gradient
- android:type="sweep"
- android:useLevel="true"
- android:startColor="#1000ceff"
- android:endColor="#ffadd252" />
-
- </shape>
-
- </rotate>
diff --git a/core/res/res/layout/preferences.xml b/core/res/res/layout/preferences.xml
index e6876ff..f0c2535 100644
--- a/core/res/res/layout/preferences.xml
+++ b/core/res/res/layout/preferences.xml
@@ -19,7 +19,8 @@
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginRight="7dip"
+ android:layout_marginRight="4dip"
android:layout_gravity="center_vertical"
- android:src="@drawable/ic_settings_indicator_next_page" />
+ android:background="@drawable/btn_circle"
+ android:src="@drawable/ic_btn_round_more" />
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 18a1355..81fd87d 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -65,13 +65,6 @@
<item>@drawable/spinner_dropdown_background</item>
<item>@drawable/title_bar</item>
<item>@drawable/title_bar_shadow</item>
- <item>@drawable/zoom_ring_arrows</item>
- <item>@drawable/zoom_ring_overview_tab</item>
- <item>@drawable/zoom_ring_thumb</item>
- <item>@drawable/zoom_ring_thumb_minus_arrow_rotatable</item>
- <item>@drawable/zoom_ring_thumb_plus_arrow_rotatable</item>
- <item>@drawable/zoom_ring_track</item>
- <item>@drawable/zoom_ring_track_absolute</item>
<!-- Visual lock screen -->
<item>@drawable/indicator_code_lock_drag_direction_green_up</item>
<item>@drawable/indicator_code_lock_drag_direction_red_up</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 30b26fa..5fa5f8d 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -371,8 +371,6 @@
<attr name="spinnerItemStyle" format="reference" />
<!-- Default MapView style. -->
<attr name="mapViewStyle" format="reference" />
- <!-- Default ZoomRing style. -->
- <attr name="zoomRingStyle" format="reference" />
<!-- =================== -->
<!-- Preference styles -->
@@ -585,29 +583,34 @@
<attr name="imeOptions">
<!-- There are no special semantics associated with this editor. -->
<flag name="normal" value="0x00000000" />
- <!-- There is no special action associated with this editor.
+ <!-- There is no specific action associated with this editor, let the
+ editor come up with its own if it can.
+ Corresponds to
+ {@link android.view.inputmethod.EditorInfo#IME_ACTION_UNSPECIFIED}. -->
+ <flag name="actionUnspecified" value="0x00000000" />
+ <!-- This editor has no action associated with it.
Corresponds to
{@link android.view.inputmethod.EditorInfo#IME_ACTION_NONE}. -->
- <flag name="actionNone" value="0x00000000" />
+ <flag name="actionNone" value="0x00000001" />
<!-- The action key performs a "go"
operation to take the user to the target of the text they typed.
Typically used, for example, when entering a URL.
{@link android.view.inputmethod.EditorInfo#IME_ACTION_GO}. -->
- <flag name="actionGo" value="0x00000001" />
+ <flag name="actionGo" value="0x00000002" />
<!-- The action key performs a "search"
operation, taking the user to the results of searching for the text
the have typed (in whatever context is appropriate).
{@link android.view.inputmethod.EditorInfo#IME_ACTION_SEARCH}. -->
- <flag name="actionSearch" value="0x00000002" />
+ <flag name="actionSearch" value="0x00000003" />
<!-- The action key performs a "send"
operation, delivering the text to its target. This is typically used
when composing a message.
{@link android.view.inputmethod.EditorInfo#IME_ACTION_SEND}. -->
- <flag name="actionSend" value="0x00000003" />
+ <flag name="actionSend" value="0x00000004" />
<!-- The action key performs a "next"
operation, taking the user to the next field that will accept text.
{@link android.view.inputmethod.EditorInfo#IME_ACTION_NEXT}. -->
- <flag name="actionNext" value="0x00000004" />
+ <flag name="actionNext" value="0x00000005" />
<!-- Used in conjunction with a custom action,
this indicates that the action should not
be available in-line as the same as a "enter" key. Typically this is
@@ -1935,34 +1938,6 @@
</attr>
<attr name="inputType" />
</declare-styleable>
- <declare-styleable name="ZoomRing">
- <!-- Defines the drawable used as the thumb. -->
- <attr name="thumbDrawable" format="reference" />
- <!-- Defines the distance of the thumb from the center of the ring. -->
- <attr name="thumbDistance" format="dimension" />
- <!-- Defines the distance from the center of the ring to the beginning of the track. -->
- <attr name="trackInnerRadius" format="dimension" />
- <!-- Defines the distance from the center of the ring to the end of the track. -->
- <attr name="trackOuterRadius" format="dimension" />
- <!-- Defines the drawable used as a hint to show which direction is zoom in. This should be
- the same size as the zoom ring's asset. It will be rotated programmatically. -->
- <attr name="zoomInArrowDrawable" format="reference" />
- <!-- Defines the drawable used as a hint to show which direction is zoom out. This should be
- the same size as the zoom ring's asset. It will be rotated programmatically. -->
- <attr name="zoomOutArrowDrawable" format="reference" />
- <!-- Defines the drawable that is laid on top of the zoom in arrow.
- For example, this could be a +. -->
- <attr name="zoomInArrowHintDrawable" format="reference" />
- <!-- Defines the drawable that is laid on top of the zoom out arrow.
- For example, this could be a -. -->
- <attr name="zoomOutArrowHintDrawable" format="reference" />
- <!-- Defines the distance of the zoom arrow hint from the center of the ring. -->
- <attr name="zoomArrowHintDistance" format="dimension" />
- <!-- Defines the offset of the zoom arrow hints from the thumb. Valid ranges are [0, 359] -->
- <attr name="zoomArrowHintOffsetAngle" format="integer" />
- <!-- Defines the drawable used to hint that the zoom ring can pan its owner. -->
- <attr name="panningArrowsDrawable" format="reference" />
- </declare-styleable>
<declare-styleable name="PopupWindow">
<attr name="popupBackground" format="reference|color" />
</declare-styleable>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 9f4d82e..54eba62 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -144,11 +144,6 @@
<item name="windowExitAnimation">@anim/search_bar_exit</item>
</style>
- <!-- Standard animations for the zoom ring. -->
- <style name="Animation.ZoomRing">
- <item name="windowEnterAnimation">@anim/zoom_ring_enter</item>
- <item name="windowExitAnimation">@anim/zoom_ring_exit</item>
- </style>
<!-- Status Bar Styles -->
<style name="TextAppearance.StatusBarTitle">
@@ -461,21 +456,6 @@
<item name="android:shadowRadius">2.75</item>
</style>
- <style name="Widget.ZoomRing">
- <item name="android:background">@android:drawable/zoom_ring_track</item>
- <item name="android:thumbDrawable">@android:drawable/zoom_ring_thumb</item>
- <item name="android:thumbDistance">63dip</item>
- <item name="android:trackInnerRadius">43dip</item>
- <item name="android:trackOuterRadius">91dip</item>
- <item name="android:zoomInArrowDrawable">@android:drawable/zoom_ring_thumb_plus_arrow_rotatable</item>
- <item name="android:zoomOutArrowDrawable">@android:drawable/zoom_ring_thumb_minus_arrow_rotatable</item>
- <item name="android:zoomInArrowHintDrawable">@android:drawable/zoom_ring_thumb_plus</item>
- <item name="android:zoomOutArrowHintDrawable">@android:drawable/zoom_ring_thumb_minus</item>
- <item name="android:zoomArrowHintDistance">69dip</item>
- <item name="android:zoomArrowHintOffsetAngle">33</item>
- <item name="android:panningArrowsDrawable">@android:drawable/zoom_ring_arrows</item>
- </style>
-
<!-- Text Appearances -->
<eat-comment />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index bde6b2a..01c46de 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -162,7 +162,6 @@
<item name="spinnerItemStyle">@android:style/Widget.TextView.SpinnerItem</item>
<item name="dropDownHintAppearance">@android:style/TextAppearance.Widget.DropDownHint</item>
<item name="keyboardViewStyle">@android:style/Widget.KeyboardView</item>
- <item name="zoomRingStyle">@android:style/Widget.ZoomRing</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>