summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/hardware/Camera.java209
-rw-r--r--core/java/android/nfc/NfcAdapter.java55
-rw-r--r--core/java/android/provider/Settings.java10
-rwxr-xr-xcore/java/android/provider/Telephony.java10
-rw-r--r--core/java/android/view/View.java16
-rw-r--r--core/java/android/view/textservice/SpellCheckerSession.java28
-rw-r--r--core/java/android/webkit/BrowserFrame.java13
-rw-r--r--core/java/android/webkit/WebView.java67
-rw-r--r--core/java/android/webkit/WebViewCore.java7
-rw-r--r--core/java/android/widget/ImageView.java24
-rw-r--r--core/java/android/widget/SpellChecker.java4
-rw-r--r--core/java/android/widget/TextView.java61
12 files changed, 428 insertions, 76 deletions
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 48adfad..3becec0 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -22,9 +22,12 @@ import android.graphics.ImageFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemProperties;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
@@ -154,6 +157,7 @@ public class Camera {
private boolean mOneShot;
private boolean mWithBuffer;
private boolean mFaceDetectionRunning = false;
+ private boolean mReleased = false;
/**
* Broadcast Action: A new picture is taken by the camera, and the entry of
@@ -303,7 +307,7 @@ public class Camera {
}
protected void finalize() {
- native_release();
+ release();
}
private native final void native_setup(Object camera_this, int cameraId);
@@ -318,6 +322,15 @@ public class Camera {
public final void release() {
native_release();
mFaceDetectionRunning = false;
+ if (mCameraSoundPlayers != null) {
+ for (CameraSoundPlayer csp: mCameraSoundPlayers) {
+ if (csp != null) {
+ csp.release();
+ }
+ }
+ mCameraSoundPlayers = null;
+ }
+ mReleased = true;
}
/**
@@ -2354,7 +2367,7 @@ public class Camera {
*
* <p>The reference code is as follows.
*
- * <pre>
+ * <pre>
* public void onOrientationChanged(int orientation) {
* if (orientation == ORIENTATION_UNKNOWN) return;
* android.hardware.Camera.CameraInfo info =
@@ -2369,7 +2382,7 @@ public class Camera {
* }
* mParameters.setRotation(rotation);
* }
- * </pre>
+ * </pre>
*
* @param rotation The rotation angle in degrees relative to the
* orientation of the camera. Rotation can only be 0,
@@ -3452,4 +3465,194 @@ public class Camera {
return result;
}
};
+
+ /**
+ * <p>The set of default system sounds for camera actions. Use this with
+ * {@link #playSound} to play an appropriate sound when implementing a
+ * custom still or video recording mechanism through the preview
+ * callbacks.</p>
+ *
+ * <p>There is no need to play sounds when using {@link #takePicture} or
+ * {@link android.media.MediaRecorder} for still images or video,
+ * respectively, as these play their own sounds when needed.</p>
+ *
+ * @see #playSound
+ * @hide
+ */
+ public static class Sound {
+ /**
+ * The sound used by {@link android.hardware.Camera#takePicture} to
+ * indicate still image capture.
+ */
+ public static final int SHUTTER_CLICK = 0;
+
+ /**
+ * A sound to indicate that focusing has completed. Because deciding
+ * when this occurs is application-dependent, this sound is not used by
+ * any methods in the Camera class.
+ */
+ public static final int FOCUS_COMPLETE = 1;
+
+ /**
+ * The sound used by {@link android.media.MediaRecorder#start} to
+ * indicate the start of video recording.
+ */
+ public static final int START_VIDEO_RECORDING = 2;
+
+ /**
+ * The sound used by {@link android.media.MediaRecorder#stop} to
+ * indicate the end of video recording.
+ */
+ public static final int STOP_VIDEO_RECORDING = 3;
+
+ private static final int NUM_SOUNDS = 4;
+ };
+
+ /**
+ * <p>Play one of the predefined platform sounds for camera actions.</p>
+ *
+ * <p>Use this method to play a platform-specific sound for various camera
+ * actions. The sound playing is done asynchronously, with the same behavior
+ * and content as the sounds played by {@link #takePicture takePicture},
+ * {@link android.media.MediaRecorder#start MediaRecorder.start}, and
+ * {@link android.media.MediaRecorder#stop MediaRecorder.stop}.</p>
+ *
+ * <p>Using this method makes it easy to match the default device sounds
+ * when recording or capturing data through the preview callbacks
+ * ({@link #setPreviewCallback setPreviewCallback},
+ * {@link #setPreviewTexture setPreviewTexture}).</p>
+ *
+ * @param soundId The type of sound to play, selected from the options in
+ * {@link android.hardware.Camera.Sound}
+ * @see android.hardware.Camera.Sound
+ * @see #takePicture
+ * @see android.media.MediaRecorder
+ * @hide
+ */
+ public void playSound(int soundId) {
+ if (mReleased) return;
+ if (mCameraSoundPlayers == null) {
+ mCameraSoundPlayers = new CameraSoundPlayer[Sound.NUM_SOUNDS];
+ }
+ if (mCameraSoundPlayers[soundId] == null) {
+ mCameraSoundPlayers[soundId] = new CameraSoundPlayer(soundId);
+ }
+ mCameraSoundPlayers[soundId].play();
+ }
+
+ private CameraSoundPlayer[] mCameraSoundPlayers;
+
+ private static class CameraSoundPlayer implements Runnable {
+ private int mSoundId;
+ private int mAudioStreamType;
+ private MediaPlayer mPlayer;
+ private Thread mThread;
+ private boolean mExit;
+ private int mPlayCount;
+
+ private static final String mShutterSound =
+ "/system/media/audio/ui/camera_click.ogg";
+ private static final String mFocusSound =
+ "/system/media/audio/ui/camera_focus.ogg";
+ private static final String mVideoStartSound =
+ "/system/media/audio/ui/VideoRecord.ogg";
+ private static final String mVideoStopSound =
+ "/system/media/audio/ui/VideoRecord.ogg";
+
+ @Override
+ public void run() {
+ String soundFilePath;
+ switch (mSoundId) {
+ case Sound.SHUTTER_CLICK:
+ soundFilePath = mShutterSound;
+ break;
+ case Sound.FOCUS_COMPLETE:
+ soundFilePath = mFocusSound;
+ break;
+ case Sound.START_VIDEO_RECORDING:
+ soundFilePath = mVideoStartSound;
+ break;
+ case Sound.STOP_VIDEO_RECORDING:
+ soundFilePath = mVideoStopSound;
+ break;
+ default:
+ Log.e(TAG, "Unknown sound " + mSoundId + " requested.");
+ return;
+ }
+ mPlayer = new MediaPlayer();
+ try {
+ mPlayer.setAudioStreamType(mAudioStreamType);
+ mPlayer.setDataSource(soundFilePath);
+ mPlayer.setLooping(false);
+ mPlayer.prepare();
+ } catch(IOException e) {
+ Log.e(TAG, "Error setting up sound " + mSoundId, e);
+ return;
+ }
+
+ while(true) {
+ try {
+ synchronized (this) {
+ while(true) {
+ if (mExit) {
+ return;
+ } else if (mPlayCount <= 0) {
+ wait();
+ } else {
+ mPlayCount--;
+ break;
+ }
+ }
+ }
+ mPlayer.start();
+ } catch (Exception e) {
+ Log.e(TAG, "Error playing sound " + mSoundId, e);
+ }
+ }
+ }
+
+ public CameraSoundPlayer(int soundId) {
+ mSoundId = soundId;
+ if (SystemProperties.get("ro.camera.sound.forced", "0").equals("0")) {
+ mAudioStreamType = AudioManager.STREAM_MUSIC;
+ } else {
+ mAudioStreamType = AudioManager.STREAM_SYSTEM_ENFORCED;
+ }
+ }
+
+ public void play() {
+ if (mThread == null) {
+ mThread = new Thread(this);
+ mThread.start();
+ }
+ synchronized (this) {
+ mPlayCount++;
+ notifyAll();
+ }
+ }
+
+ public void release() {
+ if (mThread != null) {
+ synchronized (this) {
+ mExit = true;
+ notifyAll();
+ }
+ try {
+ mThread.join();
+ } catch (InterruptedException e) {
+ }
+ mThread = null;
+ }
+ if (mPlayer != null) {
+ mPlayer.release();
+ mPlayer = null;
+ }
+ }
+
+ @Override
+ protected void finalize() {
+ release();
+ }
+ }
+
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 33310df..fe0106d 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -768,6 +768,61 @@ public final class NfcAdapter {
}
/**
+ * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
+ * @deprecated use {@link CreateNdefMessageCallback} or {@link OnNdefPushCompleteCallback}
+ * @hide
+ */
+ @Deprecated
+ public interface NdefPushCallback {
+ /**
+ * @deprecated use {@link CreateNdefMessageCallback} instead
+ */
+ @Deprecated
+ NdefMessage createMessage();
+ /**
+ * @deprecated use{@link OnNdefPushCompleteCallback} instead
+ */
+ @Deprecated
+ void onMessagePushed();
+ }
+
+ /**
+ * TODO: Remove this
+ * Converts new callbacks to old callbacks.
+ */
+ static final class LegacyCallbackWrapper implements CreateNdefMessageCallback,
+ OnNdefPushCompleteCallback {
+ final NdefPushCallback mLegacyCallback;
+ LegacyCallbackWrapper(NdefPushCallback legacyCallback) {
+ mLegacyCallback = legacyCallback;
+ }
+ @Override
+ public void onNdefPushComplete(NfcEvent event) {
+ mLegacyCallback.onMessagePushed();
+ }
+ @Override
+ public NdefMessage createNdefMessage(NfcEvent event) {
+ return mLegacyCallback.createMessage();
+ }
+ }
+
+ /**
+ * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
+ * @deprecated use {@link #setNdefPushMessageCallback} instead
+ * @hide
+ */
+ @Deprecated
+ public void enableForegroundNdefPush(Activity activity, final NdefPushCallback callback) {
+ if (activity == null || callback == null) {
+ throw new NullPointerException();
+ }
+ enforceResumed(activity);
+ LegacyCallbackWrapper callbackWrapper = new LegacyCallbackWrapper(callback);
+ mNfcActivityManager.setNdefPushMessageCallback(activity, callbackWrapper);
+ mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callbackWrapper);
+ }
+
+ /**
* Enable NDEF Push feature.
* <p>This API is for the Settings application.
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 769776e..b032169 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4077,13 +4077,6 @@ public final class Settings {
"contacts_preauth_uri_expiration";
/**
- * Whether the Messaging app posts notifications.
- * 0=disabled. 1=enabled.
- */
- public static final String MESSAGING_APP_NOTIFICATIONS = "messaging_app_notifications";
-
-
- /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -4120,8 +4113,7 @@ public final class Settings {
MOUNT_UMS_NOTIFY_ENABLED,
UI_NIGHT_MODE,
LOCK_SCREEN_OWNER_INFO,
- LOCK_SCREEN_OWNER_INFO_ENABLED,
- MESSAGING_APP_NOTIFICATIONS
+ LOCK_SCREEN_OWNER_INFO_ENABLED
};
/**
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 8eb9da1..0e6d07d 100755
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1838,15 +1838,5 @@ public final class Telephony {
public static final String EXTRA_PLMN = "plmn";
public static final String EXTRA_SHOW_SPN = "showSpn";
public static final String EXTRA_SPN = "spn";
-
- /**
- * Activity Action: Shows a dialog to turn off Messaging app notification.
- * <p>Input: Nothing.
- * <p>Output: Nothing.
- */
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_MESSAGING_APP_NOTIFICATIONS =
- "android.provider.Telephony.MESSAGING_APP_NOTIFICATIONS";
-
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 62e6ebd..dc46d42 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11402,8 +11402,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* {@link SystemClock#uptimeMillis} timebase.
*/
public void scheduleDrawable(Drawable who, Runnable what, long when) {
- if (verifyDrawable(who) && what != null && mAttachInfo != null) {
- mAttachInfo.mHandler.postAtTime(what, who, when);
+ if (verifyDrawable(who) && what != null) {
+ if (mAttachInfo != null) {
+ mAttachInfo.mHandler.postAtTime(what, who, when);
+ } else {
+ ViewRootImpl.getRunQueue().postDelayed(what, when - SystemClock.uptimeMillis());
+ }
}
}
@@ -11414,8 +11418,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @param what the action to cancel
*/
public void unscheduleDrawable(Drawable who, Runnable what) {
- if (verifyDrawable(who) && what != null && mAttachInfo != null) {
- mAttachInfo.mHandler.removeCallbacks(what, who);
+ if (verifyDrawable(who) && what != null) {
+ if (mAttachInfo != null) {
+ mAttachInfo.mHandler.removeCallbacks(what, who);
+ } else {
+ ViewRootImpl.getRunQueue().removeCallbacks(what);
+ }
}
}
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 01b114c..0eb6e27 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -146,6 +146,13 @@ public class SpellCheckerSession {
}
/**
+ * Cancel pending and running spell check tasks
+ */
+ public void cancel() {
+ mSpellCheckerSessionListenerImpl.cancel();
+ }
+
+ /**
* Finish this session and allow TextServicesManagerService to disconnect the bound spell
* checker.
*/
@@ -242,6 +249,13 @@ public class SpellCheckerSession {
}
}
+ public void cancel() {
+ if (DBG) {
+ Log.w(TAG, "cancel");
+ }
+ processOrEnqueueTask(new SpellCheckerParams(TASK_CANCEL, null, 0, false));
+ }
+
public void getSuggestionsMultiple(
TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
if (DBG) {
@@ -275,8 +289,22 @@ public class SpellCheckerSession {
if (DBG) {
Log.d(TAG, "process or enqueue task: " + mISpellCheckerSession);
}
+ SpellCheckerParams closeTask = null;
if (mISpellCheckerSession == null) {
+ if (scp.mWhat == TASK_CANCEL) {
+ while (!mPendingTasks.isEmpty()) {
+ final SpellCheckerParams tmp = mPendingTasks.poll();
+ if (tmp.mWhat == TASK_CLOSE) {
+ // Only one close task should be processed, while we need to remove all
+ // close tasks from the queue
+ closeTask = tmp;
+ }
+ }
+ }
mPendingTasks.offer(scp);
+ if (closeTask != null) {
+ mPendingTasks.offer(closeTask);
+ }
} else {
processTask(scp);
}
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 388920c..c194559 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -1404,4 +1404,17 @@ class BrowserFrame extends Handler {
native void nativeSslClientCert(int handle,
byte[] pkcs8EncodedPrivateKey,
byte[][] asn1DerEncodedCertificateChain);
+
+ /**
+ * Returns true when the contents of the frame is an RTL or vertical-rl
+ * page. This is used for determining whether a frame should be initially
+ * scrolled right-most as opposed to left-most.
+ * @return true when the frame should be initially scrolled right-most
+ * based on the text direction and writing mode.
+ */
+ /* package */ boolean getShouldStartScrolledRight() {
+ return nativeGetShouldStartScrolledRight(mNativeFrame);
+ }
+
+ private native boolean nativeGetShouldStartScrolledRight(int nativeBrowserFrame);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 35efabc..03d6511 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3254,6 +3254,26 @@ public class WebView extends AbsoluteLayout
if (mHTML5VideoViewProxy != null) {
mHTML5VideoViewProxy.pauseAndDispatch();
}
+ if (mNativeClass != 0) {
+ nativeSetPauseDrawing(mNativeClass, true);
+ }
+ }
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ updateDrawingState();
+ }
+
+ void updateDrawingState() {
+ if (mNativeClass == 0 || mIsPaused) return;
+ if (getWindowVisibility() != VISIBLE) {
+ nativeSetPauseDrawing(mNativeClass, true);
+ } else if (getVisibility() != VISIBLE) {
+ nativeSetPauseDrawing(mNativeClass, true);
+ } else {
+ nativeSetPauseDrawing(mNativeClass, false);
}
}
@@ -3265,6 +3285,9 @@ public class WebView extends AbsoluteLayout
if (mIsPaused) {
mIsPaused = false;
mWebViewCore.sendMessage(EventHub.ON_RESUME);
+ if (mNativeClass != 0) {
+ nativeSetPauseDrawing(mNativeClass, false);
+ }
}
}
@@ -5599,6 +5622,7 @@ public class WebView extends AbsoluteLayout
if (visibility != View.VISIBLE && mZoomManager != null) {
mZoomManager.dismissZoomPicker();
}
+ updateDrawingState();
}
/**
@@ -8403,6 +8427,9 @@ public class WebView extends AbsoluteLayout
setNewPicture(mDelaySetPicture, true);
mDelaySetPicture = null;
}
+ if (mIsPaused) {
+ nativeSetPauseDrawing(mNativeClass, true);
+ }
break;
case UPDATE_TEXTFIELD_TEXT_MSG_ID:
// Make sure that the textfield is currently focused
@@ -8733,27 +8760,6 @@ public class WebView extends AbsoluteLayout
isPictureAfterFirstLayout, registerPageSwapCallback);
}
final Point viewSize = draw.mViewSize;
- if (isPictureAfterFirstLayout) {
- // Reset the last sent data here since dealing with new page.
- mLastWidthSent = 0;
- mZoomManager.onFirstLayout(draw);
- if (!mDrawHistory) {
- // Do not send the scroll event for this particular
- // scroll message. Note that a scroll event may
- // still be fired if the user scrolls before the
- // message can be handled.
- mSendScrollEvent = false;
- setContentScrollTo(viewState.mScrollX, viewState.mScrollY);
- mSendScrollEvent = true;
-
- // As we are on a new page, remove the WebTextView. This
- // is necessary for page loads driven by webkit, and in
- // particular when the user was on a password field, so
- // the WebTextView was visible.
- clearTextEntry();
- }
- }
-
// We update the layout (i.e. request a layout from the
// view system) if the last view size that we sent to
// WebCore matches the view size of the picture we just
@@ -8766,7 +8772,25 @@ public class WebView extends AbsoluteLayout
mSendScrollEvent = false;
recordNewContentSize(draw.mContentSize.x,
draw.mContentSize.y, updateLayout);
+
+ if (isPictureAfterFirstLayout) {
+ // Reset the last sent data here since dealing with new page.
+ mLastWidthSent = 0;
+ mZoomManager.onFirstLayout(draw);
+ int scrollX = viewState.mShouldStartScrolledRight
+ ? getContentWidth() : viewState.mScrollX;
+ int scrollY = viewState.mScrollY;
+ setContentScrollTo(scrollX, scrollY);
+ if (!mDrawHistory) {
+ // As we are on a new page, remove the WebTextView. This
+ // is necessary for page loads driven by webkit, and in
+ // particular when the user was on a password field, so
+ // the WebTextView was visible.
+ clearTextEntry();
+ }
+ }
mSendScrollEvent = true;
+
if (DebugFlags.WEB_VIEW) {
Rect b = draw.mInvalRegion.getBounds();
Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
@@ -9584,4 +9608,5 @@ public class WebView extends AbsoluteLayout
* See {@link ComponentCallbacks2} for the trim levels and descriptions
*/
private static native void nativeOnTrimMemory(int level);
+ private static native void nativeSetPauseDrawing(int instance, boolean pause);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 754d6e9..cd61481 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1982,6 +1982,7 @@ public final class WebViewCore {
int mScrollY;
boolean mMobileSite;
boolean mIsRestored;
+ boolean mShouldStartScrolledRight;
}
static class DrawData {
@@ -2382,6 +2383,7 @@ public final class WebViewCore {
viewState.mMobileSite = false;
// for non-mobile site, we don't need minPrefWidth, set it as 0
viewState.mScrollX = 0;
+ viewState.mShouldStartScrolledRight = false;
Message.obtain(mWebView.mPrivateHandler,
WebView.UPDATE_ZOOM_RANGE, viewState).sendToTarget();
return;
@@ -2412,6 +2414,11 @@ public final class WebViewCore {
mInitialViewState.mDefaultScale = adjust;
mInitialViewState.mScrollX = mRestoredX;
mInitialViewState.mScrollY = mRestoredY;
+ mInitialViewState.mShouldStartScrolledRight = (mRestoredX == 0)
+ && (mRestoredY == 0)
+ && (mBrowserFrame != null)
+ && mBrowserFrame.getShouldStartScrolledRight();
+
mInitialViewState.mMobileSite = (0 == mViewportWidth);
if (mIsRestored) {
mInitialViewState.mIsRestored = true;
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index b24dd69..c1e36ed 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -1035,4 +1035,28 @@ public class ImageView extends View {
mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
}
}
+
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+ if (mDrawable != null) {
+ mDrawable.setVisible(visibility == VISIBLE, false);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mDrawable != null) {
+ mDrawable.setVisible(getVisibility() == VISIBLE, false);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mDrawable != null) {
+ mDrawable.setVisible(false, false);
+ }
+ }
}
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 87c3e9b..ebb2604 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -76,7 +76,7 @@ public class SpellChecker implements SpellCheckerSessionListener {
mIds = new int[size];
mSpellCheckSpans = new SpellCheckSpan[size];
- setLocale(mTextView.getLocale());
+ setLocale(mTextView.getTextServicesLocale());
mCookie = hashCode();
}
@@ -173,7 +173,7 @@ public class SpellChecker implements SpellCheckerSessionListener {
}
public void spellCheck(int start, int end) {
- final Locale locale = mTextView.getLocale();
+ final Locale locale = mTextView.getTextServicesLocale();
if (mCurrentLocale == null || (!(mCurrentLocale.equals(locale)))) {
setLocale(locale);
// Re-check the entire text
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5833afd..bc8721a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -36,7 +36,6 @@ import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.ExtractEditText;
-import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -101,7 +100,6 @@ import android.util.Log;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ActionMode.Callback;
-import android.view.ContextMenu;
import android.view.DragEvent;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
@@ -133,6 +131,8 @@ import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
+import android.view.textservice.SpellCheckerSubtype;
+import android.view.textservice.TextServicesManager;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.RemoteViews.RemoteView;
@@ -8355,10 +8355,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// When the cursor moves, the word that was typed may need spell check
mSpellChecker.onSelectionChanged();
}
- if (isCursorInsideEasyCorrectionSpan()) {
- showSuggestions();
- } else if (hasInsertionController()) {
- getInsertionController().show();
+ if (!extractedTextModeWillBeStarted()) {
+ if (isCursorInsideEasyCorrectionSpan()) {
+ showSuggestions();
+ } else if (hasInsertionController()) {
+ getInsertionController().show();
+ }
}
}
@@ -8904,21 +8906,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* This is a temporary method. Future versions may support multi-locale text.
*
- * @return The current locale used in this TextView, based on the current IME's locale,
- * or the system default locale if this is not defined.
+ * @return The locale that should be used for a word iterator and a spell checker
+ * in this TextView, based on the current spell checker settings,
+ * the current IME's locale, or the system default locale.
* @hide
*/
- public Locale getLocale() {
+ public Locale getTextServicesLocale() {
Locale locale = Locale.getDefault();
- final InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) {
- final InputMethodSubtype currentInputMethodSubtype = imm.getCurrentInputMethodSubtype();
- if (currentInputMethodSubtype != null) {
- String localeString = currentInputMethodSubtype.getLocale();
- if (!TextUtils.isEmpty(localeString)) {
- locale = new Locale(localeString);
- }
- }
+ final TextServicesManager textServicesManager = (TextServicesManager)
+ mContext.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
+ final SpellCheckerSubtype subtype = textServicesManager.getCurrentSpellCheckerSubtype(true);
+ if (subtype != null) {
+ locale = new Locale(subtype.getLocale());
}
return locale;
}
@@ -8933,7 +8932,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
public WordIterator getWordIterator() {
if (mWordIterator == null) {
- mWordIterator = new WordIterator(getLocale());
+ mWordIterator = new WordIterator(getTextServicesLocale());
}
return mWordIterator;
}
@@ -10113,27 +10112,35 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- final InputMethodManager imm = InputMethodManager.peekInstance();
- boolean extractedTextModeWillBeStartedFullScreen = !(this instanceof ExtractEditText) &&
- imm != null && imm.isFullscreenMode();
+ boolean willExtract = extractedTextModeWillBeStarted();
// Do not start the action mode when extracted text will show up full screen, thus
// immediately hiding the newly created action bar, which would be visually distracting.
- if (!extractedTextModeWillBeStartedFullScreen) {
+ if (!willExtract) {
ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
mSelectionActionMode = startActionMode(actionModeCallback);
}
- final boolean selectionStarted = mSelectionActionMode != null ||
- extractedTextModeWillBeStartedFullScreen;
- if (selectionStarted && !mTextIsSelectable && imm != null && mSoftInputShownOnFocus) {
+ final boolean selectionStarted = mSelectionActionMode != null || willExtract;
+ if (selectionStarted && !mTextIsSelectable && mSoftInputShownOnFocus) {
// Show the IME to be able to replace text, except when selecting non editable text.
- imm.showSoftInput(this, 0, null);
+ final InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ imm.showSoftInput(this, 0, null);
+ }
}
return selectionStarted;
}
+ private boolean extractedTextModeWillBeStarted() {
+ if (!(this instanceof ExtractEditText)) {
+ final InputMethodManager imm = InputMethodManager.peekInstance();
+ return imm != null && imm.isFullscreenMode();
+ }
+ return false;
+ }
+
private void stopSelectionActionMode() {
if (mSelectionActionMode != null) {
// This will hide the mSelectionModifierCursorController