summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/service/dreams/Sandman.java122
-rw-r--r--core/java/android/webkit/AccessibilityInjector.java29
-rw-r--r--core/java/android/webkit/WebView.java1
-rw-r--r--core/java/android/webkit/WebViewClassic.java41
4 files changed, 176 insertions, 17 deletions
diff --git a/core/java/android/service/dreams/Sandman.java b/core/java/android/service/dreams/Sandman.java
new file mode 100644
index 0000000..70142ce
--- /dev/null
+++ b/core/java/android/service/dreams/Sandman.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 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.service.dreams;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Slog;
+
+/**
+ * Internal helper for launching dreams to ensure consistency between the
+ * <code>UiModeManagerService</code> system service and the <code>Somnambulator</code> activity.
+ *
+ * @hide
+ */
+public final class Sandman {
+ private static final String TAG = "Sandman";
+
+ private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
+ private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
+
+ // The component name of a special dock app that merely launches a dream.
+ // We don't want to launch this app when docked because it causes an unnecessary
+ // activity transition. We just want to start the dream.
+ private static final ComponentName SOMNAMBULATOR_COMPONENT =
+ new ComponentName("com.android.systemui", "com.android.systemui.Somnambulator");
+
+
+ // The sandman is eternal. No one instantiates him.
+ private Sandman() {
+ }
+
+ /**
+ * Returns true if the specified dock app intent should be started.
+ * False if we should dream instead, if appropriate.
+ */
+ public static boolean shouldStartDockApp(Context context, Intent intent) {
+ ComponentName name = intent.resolveActivity(context.getPackageManager());
+ return name != null && !name.equals(SOMNAMBULATOR_COMPONENT);
+ }
+
+ /**
+ * Starts a dream manually.
+ */
+ public static void startDreamByUserRequest(Context context) {
+ startDream(context, false);
+ }
+
+ /**
+ * Starts a dream when docked if the system has been configured to do so,
+ * otherwise does nothing.
+ */
+ public static void startDreamWhenDockedIfAppropriate(Context context) {
+ if (!isScreenSaverEnabled(context)
+ || !isScreenSaverActivatedOnDock(context)) {
+ Slog.i(TAG, "Dreams currently disabled for docks.");
+ return;
+ }
+
+ startDream(context, true);
+ }
+
+ private static void startDream(Context context, boolean docked) {
+ try {
+ IDreamManager dreamManagerService = IDreamManager.Stub.asInterface(
+ ServiceManager.getService(DreamService.DREAM_SERVICE));
+ if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
+ if (docked) {
+ Slog.i(TAG, "Activating dream while docked.");
+
+ // Wake up.
+ // The power manager will wake up the system automatically when it starts
+ // receiving power from a dock but there is a race between that happening
+ // and the UI mode manager starting a dream. We want the system to already
+ // be awake by the time this happens. Otherwise the dream may not start.
+ PowerManager powerManager =
+ (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ powerManager.wakeUp(SystemClock.uptimeMillis());
+ } else {
+ Slog.i(TAG, "Activating dream by user request.");
+ }
+
+ // Dream.
+ dreamManagerService.dream();
+ }
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Could not start dream when docked.", ex);
+ }
+ }
+
+ private static boolean isScreenSaverEnabled(Context context) {
+ return Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED,
+ UserHandle.USER_CURRENT) != 0;
+ }
+
+ private static boolean isScreenSaverActivatedOnDock(Context context) {
+ return Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+ DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0;
+ }
+}
diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java
index d6576e1..357a16e 100644
--- a/core/java/android/webkit/AccessibilityInjector.java
+++ b/core/java/android/webkit/AccessibilityInjector.java
@@ -96,11 +96,26 @@ class AccessibilityInjector {
// Template for JavaScript that performs AndroidVox actions.
private static final String ACCESSIBILITY_ANDROIDVOX_TEMPLATE =
- "cvox.AndroidVox.performAction('%1s')";
+ "(function() {" +
+ " if ((typeof(cvox) != 'undefined')"+
+ " && (typeof(cvox.ChromeVox) != 'undefined')" +
+ " && (typeof(cvox.AndroidVox) != 'undefined')" +
+ " && cvox.ChromeVox.isActive) {" +
+ " return cvox.AndroidVox.performAction('%1s');" +
+ " } else {" +
+ " return false;" +
+ " }" +
+ "})()";
// JS code used to shut down an active AndroidVox instance.
private static final String TOGGLE_CVOX_TEMPLATE =
- "javascript:(function() { cvox.ChromeVox.host.activateOrDeactivateChromeVox(%b); })();";
+ "javascript:(function() {" +
+ " if ((typeof(cvox) != 'undefined')"+
+ " && (typeof(cvox.ChromeVox) != 'undefined')" +
+ " && (typeof(cvox.ChromeVox.host) != 'undefined')) {" +
+ " cvox.ChromeVox.host.activateOrDeactivateChromeVox(%b);" +
+ " }" +
+ "})();";
/**
* Creates an instance of the AccessibilityInjector based on
@@ -776,20 +791,26 @@ class AccessibilityInjector {
while (true) {
try {
if (mResultId == resultId) {
+ if (DEBUG)
+ Log.w(TAG, "Received CVOX result");
return true;
}
if (mResultId > resultId) {
+ if (DEBUG)
+ Log.w(TAG, "Obsolete CVOX result");
return false;
}
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
waitTimeMillis = RESULT_TIMEOUT - elapsedTimeMillis;
if (waitTimeMillis <= 0) {
+ if (DEBUG)
+ Log.w(TAG, "Timed out while waiting for CVOX result");
return false;
}
mResultLock.wait(waitTimeMillis);
} catch (InterruptedException ie) {
if (DEBUG)
- Log.w(TAG, "Timed out while waiting for CVOX result");
+ Log.w(TAG, "Interrupted while waiting for CVOX result");
/* ignore */
}
}
@@ -805,6 +826,8 @@ class AccessibilityInjector {
@JavascriptInterface
@SuppressWarnings("unused")
public void onResult(String id, String result) {
+ if (DEBUG)
+ Log.w(TAG, "Saw CVOX result of '" + result + "'");
final long resultId;
try {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4202a7f..6df7820 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1480,7 +1480,6 @@ public class WebView extends AbsoluteLayout
*
* @param listener an implementation of WebView.PictureListener
* @deprecated This method is now obsolete.
- * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
*/
@Deprecated
public void setPictureListener(PictureListener listener) {
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index d68511c..7d0d0ba 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -5185,7 +5185,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
if (cm.hasPrimaryClip()) {
Point cursorPoint = new Point(contentToViewX(mSelectCursorBase.x),
contentToViewY(mSelectCursorBase.y));
- Point cursorTop = calculateCaretTop();
+ Point cursorTop = calculateBaseCaretTop();
cursorTop.set(contentToViewX(cursorTop.x),
contentToViewY(cursorTop.y));
@@ -5229,17 +5229,22 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
return scale;
}
+ private Point calculateBaseCaretTop() {
+ return calculateCaretTop(mSelectCursorBase, mSelectCursorBaseTextQuad);
+ }
+
+ private Point calculateDraggingCaretTop() {
+ return calculateCaretTop(mSelectDraggingCursor, mSelectDraggingTextQuad);
+ }
+
/**
* Assuming arbitrary shape of a quadralateral forming text bounds, this
* calculates the top of a caret.
*/
- private Point calculateCaretTop() {
- float scale = scaleAlongSegment(mSelectCursorBase.x, mSelectCursorBase.y,
- mSelectCursorBaseTextQuad.p4, mSelectCursorBaseTextQuad.p3);
- int x = Math.round(scaleCoordinate(scale,
- mSelectCursorBaseTextQuad.p1.x, mSelectCursorBaseTextQuad.p2.x));
- int y = Math.round(scaleCoordinate(scale,
- mSelectCursorBaseTextQuad.p1.y, mSelectCursorBaseTextQuad.p2.y));
+ private static Point calculateCaretTop(Point base, QuadF quad) {
+ float scale = scaleAlongSegment(base.x, base.y, quad.p4, quad.p3);
+ int x = Math.round(scaleCoordinate(scale, quad.p1.x, quad.p2.x));
+ int y = Math.round(scaleCoordinate(scale, quad.p1.y, quad.p2.y));
return new Point(x, y);
}
@@ -5269,12 +5274,20 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
return true;
}
- private void updateWebkitSelection() {
+ private void updateWebkitSelection(boolean isSnapped) {
int handleId = (mSelectDraggingCursor == mSelectCursorBase)
? HANDLE_ID_BASE : HANDLE_ID_EXTENT;
+ int x = mSelectDraggingCursor.x;
+ int y = mSelectDraggingCursor.y;
+ if (isSnapped) {
+ // "center" the cursor in the snapping quad
+ Point top = calculateDraggingCaretTop();
+ x = Math.round((top.x + x) / 2);
+ y = Math.round((top.y + y) / 2);
+ }
mWebViewCore.removeMessages(EventHub.SELECT_TEXT);
mWebViewCore.sendMessageAtFrontOfQueue(EventHub.SELECT_TEXT,
- mSelectDraggingCursor.x, mSelectDraggingCursor.y, (Integer)handleId);
+ x, y, (Integer)handleId);
}
private void resetCaretTimer() {
@@ -5616,7 +5629,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
Math.max(0, mEditTextContentBounds.top - buffer),
mEditTextContentBounds.right + buffer,
mEditTextContentBounds.bottom + buffer);
- Point caretTop = calculateCaretTop();
+ Point caretTop = calculateBaseCaretTop();
if (visibleRect.width() < mEditTextContentBounds.width()) {
// The whole edit won't fit in the width, so use the caret rect
if (mSelectCursorBase.x < caretTop.x) {
@@ -5947,10 +5960,12 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
} else {
endScrollEdit();
}
+ boolean snapped = false;
if (inCursorText || (mIsEditingText && !inEditBounds)) {
snapDraggingCursor();
+ snapped = true;
}
- updateWebkitSelection();
+ updateWebkitSelection(snapped);
if (!inCursorText && mIsEditingText && inEditBounds) {
// Visually snap even if we have moved the handle.
snapDraggingCursor();
@@ -6277,7 +6292,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
int oldX = mSelectDraggingCursor.x;
int oldY = mSelectDraggingCursor.y;
mSelectDraggingCursor.set(selectionX, selectionY);
- updateWebkitSelection();
+ updateWebkitSelection(false);
scrollEditText(scrollX, scrollY);
mSelectDraggingCursor.set(oldX, oldY);
}