summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk10
-rw-r--r--api/current.txt79
-rw-r--r--core/java/android/app/ActivityManagerNative.java4
-rw-r--r--core/java/android/app/ApplicationThreadNative.java4
-rw-r--r--core/java/android/app/ContextImpl.java6
-rw-r--r--core/java/android/app/FragmentManager.java1
-rw-r--r--core/java/android/content/Context.java9
-rw-r--r--core/java/android/inputmethodservice/ExtractEditLayout.java5
-rw-r--r--core/java/android/net/EthernetDataTracker.java4
-rw-r--r--core/java/android/net/INetworkManagementEventObserver.aidl10
-rw-r--r--core/java/android/net/VpnBuilder.java413
-rw-r--r--core/java/android/os/Handler.java9
-rw-r--r--core/java/android/preference/PreferenceActivity.java10
-rw-r--r--core/java/android/provider/ContactsContract.java7
-rw-r--r--core/java/android/provider/Settings.java12
-rw-r--r--core/java/android/service/textservice/SpellCheckerService.java140
-rw-r--r--core/java/android/service/textservice/SpellCheckerSession.java271
-rw-r--r--core/java/android/util/JsonReader.java6
-rw-r--r--core/java/android/view/CollapsibleActionView.java41
-rw-r--r--core/java/android/view/DisplayList.java9
-rw-r--r--core/java/android/view/GLES20Canvas.java51
-rw-r--r--core/java/android/view/GLES20DisplayList.java86
-rw-r--r--core/java/android/view/GLES20RecordingCanvas.java96
-rw-r--r--core/java/android/view/HardwareRenderer.java6
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/view/ViewDebug.java163
-rw-r--r--core/java/android/view/textservice/SpellCheckerInfo.aidl19
-rw-r--r--core/java/android/view/textservice/SpellCheckerInfo.java112
-rw-r--r--core/java/android/view/textservice/SuggestionsInfo.aidl19
-rw-r--r--core/java/android/view/textservice/SuggestionsInfo.java176
-rw-r--r--core/java/android/view/textservice/TextInfo.aidl19
-rw-r--r--core/java/android/view/textservice/TextInfo.java117
-rw-r--r--core/java/android/view/textservice/TextServicesManager.java106
-rw-r--r--core/java/android/widget/AbsListView.java3
-rw-r--r--core/java/com/android/internal/textservice/ISpellCheckerService.aidl29
-rw-r--r--core/java/com/android/internal/textservice/ISpellCheckerSession.aidl28
-rw-r--r--core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl26
-rw-r--r--core/java/com/android/internal/textservice/ITextServicesManager.aidl35
-rw-r--r--core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl29
-rw-r--r--core/java/com/android/internal/view/menu/MenuBuilder.java63
-rw-r--r--core/java/com/android/internal/view/menu/MenuItemImpl.java3
-rw-r--r--core/java/com/android/internal/view/menu/SubMenuBuilder.java9
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java10
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp23
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/anim/screen_rotate_minus_90_enter.xml5
-rw-r--r--core/res/res/anim/screen_rotate_plus_90_enter.xml5
-rwxr-xr-xcore/res/res/values/strings.xml6
-rw-r--r--docs/html/guide/developing/tools/adb.jd2
-rw-r--r--docs/html/guide/topics/intents/intents-filters.jd2
-rw-r--r--docs/html/guide/topics/manifest/activity-element.jd4
-rw-r--r--docs/html/guide/topics/providers/content-providers.jd2
-rw-r--r--graphics/jni/android_renderscript_RenderScript.cpp1
-rw-r--r--include/media/stagefright/DataSource.h5
-rw-r--r--libs/gui/SurfaceTextureClient.cpp3
-rw-r--r--libs/hwui/DisplayListRenderer.cpp11
-rw-r--r--libs/hwui/DisplayListRenderer.h4
-rw-r--r--libs/ui/FramebufferNativeWindow.cpp28
-rw-r--r--media/libmedia/mediaplayer.cpp2
-rw-r--r--media/libstagefright/NuCachedSource2.cpp61
-rw-r--r--media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp34
-rw-r--r--media/libstagefright/include/ChromiumHTTPDataSource.h2
-rw-r--r--media/libstagefright/include/NuCachedSource2.h6
-rw-r--r--packages/SystemUI/res/values/config.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java5
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java17
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java88
-rw-r--r--services/audioflinger/AudioFlinger.cpp2
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java8
-rw-r--r--services/java/com/android/server/NetworkManagementService.java85
-rw-r--r--services/java/com/android/server/SystemServer.java11
-rw-r--r--services/java/com/android/server/TextServicesManagerService.java346
-rw-r--r--services/java/com/android/server/ThrottleService.java1
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java2
-rw-r--r--services/java/com/android/server/connectivity/Vpn.java2
-rw-r--r--services/java/com/android/server/wm/BlackFrame.java4
-rw-r--r--services/surfaceflinger/SurfaceTextureLayer.cpp4
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneBase.java4
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java39
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java8
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java2
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java2
-rw-r--r--wifi/java/android/net/wifi/WifiWatchdogStateMachine.java2
84 files changed, 2785 insertions, 320 deletions
diff --git a/Android.mk b/Android.mk
index 335fb732b214..3b0fc599ed17 100644
--- a/Android.mk
+++ b/Android.mk
@@ -158,6 +158,11 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/os/IResultReceiver.aidl \
core/java/com/android/internal/statusbar/IStatusBar.aidl \
core/java/com/android/internal/statusbar/IStatusBarService.aidl \
+ core/java/com/android/internal/textservice/ISpellCheckerService.aidl \
+ core/java/com/android/internal/textservice/ISpellCheckerSession.aidl \
+ core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl \
+ core/java/com/android/internal/textservice/ITextServicesManager.aidl \
+ core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl \
core/java/com/android/internal/view/IInputContext.aidl \
core/java/com/android/internal/view/IInputContextCallback.aidl \
core/java/com/android/internal/view/IInputMethod.aidl \
@@ -266,6 +271,11 @@ aidl_files := \
frameworks/base/core/java/android/view/Surface.aidl \
frameworks/base/core/java/android/view/WindowManager.aidl \
frameworks/base/core/java/android/widget/RemoteViews.aidl \
+ frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerService.aidl \
+ frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl \
+ frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl \
+ frameworks/base/core/java/com/android/internal/textservice/ITextServicesManager.aidl \
+ frameworks/base/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl \
frameworks/base/core/java/com/android/internal/view/IInputContext.aidl \
frameworks/base/core/java/com/android/internal/view/IInputMethod.aidl \
frameworks/base/core/java/com/android/internal/view/IInputMethodCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index 93f7a8f26b88..f88001d825f1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21,6 +21,7 @@ package android {
field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
+ field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
@@ -4783,6 +4784,7 @@ package android.content {
field public static final java.lang.String SENSOR_SERVICE = "sensor";
field public static final java.lang.String STORAGE_SERVICE = "storage";
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
+ field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
field public static final java.lang.String UI_MODE_SERVICE = "uimode";
field public static final java.lang.String USB_SERVICE = "usb";
field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
@@ -17941,6 +17943,30 @@ package android.security {
}
+package android.service.textservice {
+
+ public abstract class SpellCheckerService extends android.app.Service {
+ ctor public SpellCheckerService();
+ method public void cancel();
+ method public abstract android.view.textservice.SuggestionsInfo getSuggestions(android.view.textservice.TextInfo, int, java.lang.String);
+ method public android.view.textservice.SuggestionsInfo[] getSuggestionsMultiple(android.view.textservice.TextInfo[], java.lang.String, int, boolean);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ field public static final java.lang.String SERVICE_INTERFACE;
+ }
+
+ public class SpellCheckerSession {
+ method public void close();
+ method public void getSuggestions(android.view.textservice.TextInfo, int);
+ method public void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
+ method public boolean isSessionDisconnected();
+ }
+
+ public static abstract interface SpellCheckerSession.SpellCheckerSessionListener {
+ method public abstract void onGetSuggestions(android.view.textservice.SuggestionsInfo[]);
+ }
+
+}
+
package android.service.wallpaper {
public abstract class WallpaperService extends android.app.Service {
@@ -21004,6 +21030,11 @@ package android.view {
method public void onPrepareSubMenu(android.view.SubMenu);
}
+ public abstract interface CollapsibleActionView {
+ method public abstract void onActionViewCollapsed();
+ method public abstract void onActionViewExpanded();
+ }
+
public abstract interface ContextMenu implements android.view.Menu {
method public abstract void clearHeader();
method public abstract android.view.ContextMenu setHeaderIcon(int);
@@ -24016,6 +24047,54 @@ package android.view.inputmethod {
}
+package android.view.textservice {
+
+ public final class SpellCheckerInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.content.ComponentName getComponent();
+ method public java.lang.String getId();
+ method public java.lang.String getPackageName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public final class SuggestionsInfo implements android.os.Parcelable {
+ ctor public SuggestionsInfo(int, java.lang.String[]);
+ ctor public SuggestionsInfo(int, java.lang.String[], int, int);
+ ctor public SuggestionsInfo(android.os.Parcel);
+ method public int describeContents();
+ method public int getCookie();
+ method public int getSequence();
+ method public java.lang.String getSuggestionAt(int);
+ method public int getSuggestionsAttributes();
+ method public int getSuggestionsCount();
+ method public void setCookieAndSequence(int, int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1
+ field public static final int RESULT_ATTR_LOOKS_TYPO = 4; // 0x4
+ field public static final int RESULT_ATTR_SUGGESTIONS_AVAILABLE = 2; // 0x2
+ }
+
+ public final class TextInfo implements android.os.Parcelable {
+ ctor public TextInfo(java.lang.String);
+ ctor public TextInfo(java.lang.String, int, int);
+ ctor public TextInfo(android.os.Parcel);
+ method public int describeContents();
+ method public int getCookie();
+ method public int getSequence();
+ method public java.lang.String getText();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public final class TextServicesManager {
+ method public android.view.textservice.SpellCheckerInfo getCurrentSpellChecker(java.util.Locale);
+ method public android.service.textservice.SpellCheckerSession newSpellCheckerSession(android.view.textservice.SpellCheckerInfo, java.util.Locale, android.service.textservice.SpellCheckerSession.SpellCheckerSessionListener);
+ }
+
+}
+
package android.webkit {
public final deprecated class CacheManager {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 2178971a3453..b7cd829563c9 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1104,10 +1104,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
data.enforceInterface(IActivityManager.descriptor);
String process = data.readString();
boolean start = data.readInt() != 0;
+ int profileType = data.readInt();
String path = data.readString();
ParcelFileDescriptor fd = data.readInt() != 0
? data.readFileDescriptor() : null;
- int profileType = data.readInt();
boolean res = profileControl(process, start, path, fd, profileType);
reply.writeNoException();
reply.writeInt(res ? 1 : 0);
@@ -2896,6 +2896,7 @@ class ActivityManagerProxy implements IActivityManager
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(process);
data.writeInt(start ? 1 : 0);
+ data.writeInt(profileType);
data.writeString(path);
if (fd != null) {
data.writeInt(1);
@@ -2903,7 +2904,6 @@ class ActivityManagerProxy implements IActivityManager
} else {
data.writeInt(0);
}
- data.writeInt(profileType);
mRemote.transact(PROFILE_CONTROL_TRANSACTION, data, reply, 0);
reply.readException();
boolean res = reply.readInt() != 0;
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index c8a3a9474112..9a5b527d7c5b 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -376,10 +376,10 @@ public abstract class ApplicationThreadNative extends Binder
{
data.enforceInterface(IApplicationThread.descriptor);
boolean start = data.readInt() != 0;
+ int profileType = data.readInt();
String path = data.readString();
ParcelFileDescriptor fd = data.readInt() != 0
? data.readFileDescriptor() : null;
- int profileType = data.readInt();
profilerControl(start, path, fd, profileType);
return true;
}
@@ -941,6 +941,7 @@ class ApplicationThreadProxy implements IApplicationThread {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeInt(start ? 1 : 0);
+ data.writeInt(profileType);
data.writeString(path);
if (fd != null) {
data.writeInt(1);
@@ -948,7 +949,6 @@ class ApplicationThreadProxy implements IApplicationThread {
} else {
data.writeInt(0);
}
- data.writeInt(profileType);
mRemote.transact(PROFILER_CONTROL_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d2323e7defec..6289730cb56e 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -83,6 +83,7 @@ import android.view.ContextThemeWrapper;
import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.InputMethodManager;
+import android.view.textservice.TextServicesManager;
import android.accounts.AccountManager;
import android.accounts.IAccountManager;
import android.app.admin.DevicePolicyManager;
@@ -320,6 +321,11 @@ class ContextImpl extends Context {
return InputMethodManager.getInstance(ctx);
}});
+ registerService(TEXT_SERVICES_MANAGER_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return TextServicesManager.getInstance();
+ }});
+
registerService(KEYGUARD_SERVICE, new ServiceFetcher() {
public Object getService(ContextImpl ctx) {
// TODO: why isn't this caching it? It wasn't
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index c82c9ecf7a8f..789d3a692775 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1695,6 +1695,7 @@ final class FragmentManagerImpl extends FragmentManager {
public void dispatchDestroy() {
mDestroyed = true;
+ execPendingActions();
moveToState(Fragment.INITIALIZING, false);
mActivity = null;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fed6d815c9f2..0a2253c8dc75 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1612,6 +1612,15 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.view.textservice.TextServicesManager} for accessing
+ * text services.
+ *
+ * @see #getSystemService
+ */
+ public static final String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.appwidget.AppWidgetManager} for accessing AppWidgets.
*
* @hide
diff --git a/core/java/android/inputmethodservice/ExtractEditLayout.java b/core/java/android/inputmethodservice/ExtractEditLayout.java
index eafff49528f5..5cfa998857b7 100644
--- a/core/java/android/inputmethodservice/ExtractEditLayout.java
+++ b/core/java/android/inputmethodservice/ExtractEditLayout.java
@@ -172,7 +172,10 @@ public class ExtractEditLayout extends LinearLayout {
@Override
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
- return mCallback.onActionItemClicked(this, item);
+ if (mCallback != null) {
+ return mCallback.onActionItemClicked(this, item);
+ }
+ return false;
}
@Override
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index a866436ed77d..b035c51d3da5 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -103,6 +103,10 @@ public class EthernetDataTracker implements NetworkStateTracker {
public void interfaceRemoved(String iface) {
mTracker.interfaceRemoved(iface);
}
+
+ public void limitReached(String limitName, String iface) {
+ // Ignored.
+ }
}
private EthernetDataTracker() {
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index 4436e6e444ee..a97f2030a146 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -52,4 +52,14 @@ interface INetworkManagementEventObserver {
* @param iface The interface.
*/
void interfaceRemoved(String iface);
+
+ /**
+ * A networking quota limit has been reached. The quota might not
+ * be specific to an interface.
+ *
+ * @param limitName The name of the limit that triggered.
+ * @param iface The interface on which the limit was detected.
+ */
+ void limitReached(String limitName, String iface);
+
}
diff --git a/core/java/android/net/VpnBuilder.java b/core/java/android/net/VpnBuilder.java
new file mode 100644
index 000000000000..458252345152
--- /dev/null
+++ b/core/java/android/net/VpnBuilder.java
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2011 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.net;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.net.VpnConfig;
+
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.DatagramSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+
+/**
+ * VpnBuilder is a framework which enables applications to build their
+ * own VPN solutions. In general, it creates a virtual network interface,
+ * configures addresses and routing rules, and returns a file descriptor
+ * to the application. Each read from the descriptor retrieves an outgoing
+ * packet which was routed to the interface. Each write to the descriptor
+ * injects an incoming packet just like it was received from the interface.
+ * The framework is running on Internet Protocol (IP), so packets are
+ * always started with IP headers. The application then completes a VPN
+ * connection by processing and exchanging packets with a remote server
+ * over a secured tunnel.
+ *
+ * <p>Letting applications intercept packets raises huge security concerns.
+ * Besides, a VPN application can easily break the network, and two of them
+ * may conflict with each other. The framework takes several actions to
+ * address these issues. Here are some key points:
+ * <ul>
+ * <li>User action is required to create a VPN connection.</li>
+ * <li>There can be only one VPN connection running at the same time. The
+ * existing interface is deactivated when a new one is created.</li>
+ * <li>A system-managed notification is shown during the lifetime of a
+ * VPN connection.</li>
+ * <li>A system-managed dialog gives the information of the current VPN
+ * connection. It also provides a button to disconnect.</li>
+ * <li>The network is restored automatically when the file descriptor is
+ * closed. It also covers the cases when a VPN application is crashed
+ * or killed by the system.</li>
+ * </ul>
+ *
+ * <p>There are two primary methods in this class: {@link #prepare} and
+ * {@link #establish}. The former deals with the user action and stops
+ * the existing VPN connection created by another application. The latter
+ * creates a VPN interface using the parameters supplied to this builder.
+ * An application must call {@link #prepare} to grant the right to create
+ * an interface, and it can be revoked at any time by another application.
+ * The application got revoked is notified by an {@link #ACTION_VPN_REVOKED}
+ * broadcast. Here are the general steps to create a VPN connection:
+ * <ol>
+ * <li>When the user press the button to connect, call {@link #prepare}
+ * and launch the intent if necessary.</li>
+ * <li>Register a receiver for {@link #ACTION_VPN_REVOKED} broadcasts.
+ * <li>Connect to the remote server and negotiate the network parameters
+ * of the VPN connection.</li>
+ * <li>Use those parameters to configure a VpnBuilder and create a VPN
+ * interface by calling {@link #establish}.</li>
+ * <li>Start processing packets between the returned file descriptor and
+ * the VPN tunnel.</li>
+ * <li>When an {@link #ACTION_VPN_REVOKED} broadcast is received, the
+ * interface is already deactivated by the framework. Close the file
+ * descriptor and shut down the VPN tunnel gracefully.
+ * </ol>
+ * Methods in this class can be used in activities and services. However,
+ * the intent returned from {@link #prepare} must be launched from an
+ * activity. The broadcast receiver can be registered at any time, but doing
+ * it before calling {@link #establish} effectively avoids race conditions.
+ *
+ * <p class="note">Using this class requires
+ * {@link android.Manifest.permission#VPN} permission.
+ * @hide
+ */
+public class VpnBuilder {
+
+ /**
+ * Broadcast intent action indicating that the VPN application has been
+ * revoked. This can be only received by the target application on the
+ * receiver explicitly registered using {@link Context#registerReceiver}.
+ *
+ * <p>This is a protected intent that can only be sent by the system.
+ */
+ public static final String ACTION_VPN_REVOKED = VpnConfig.ACTION_VPN_REVOKED;
+
+ /**
+ * Use IConnectivityManager instead since those methods are hidden and
+ * not available in ConnectivityManager.
+ */
+ private static IConnectivityManager getService() {
+ return IConnectivityManager.Stub.asInterface(
+ ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+ }
+
+ /**
+ * Prepare to establish a VPN connection. This method returns {@code null}
+ * if the VPN application is already prepared. Otherwise, it returns an
+ * {@link Intent} to a system activity. The application should launch the
+ * activity using {@link Activity#startActivityForResult} to get itself
+ * prepared. The activity may pop up a dialog to require user action, and
+ * the result will come back to the application through its
+ * {@link Activity#onActivityResult}. The application becomes prepared if
+ * the result is {@link Activity#RESULT_OK}, and it is granted to create a
+ * VPN interface by calling {@link #establish}.
+ *
+ * <p>Only one application can be granted at the same time. The right
+ * is revoked when another application is granted. The application
+ * losing the right will be notified by an {@link #ACTION_VPN_REVOKED}
+ * broadcast, and its VPN interface will be deactivated by the system.
+ * The application should then notify the remote server and disconnect
+ * gracefully. Unless the application becomes prepared again, subsequent
+ * calls to {@link #establish} will return {@code null}.
+ *
+ * @see #establish
+ * @see #ACTION_VPN_REVOKED
+ */
+ public static Intent prepare(Context context) {
+ try {
+ if (getService().prepareVpn(context.getPackageName(), null)) {
+ return null;
+ }
+ } catch (RemoteException e) {
+ // ignore
+ }
+ return VpnConfig.getIntentForConfirmation();
+ }
+
+ private VpnConfig mConfig = new VpnConfig();
+ private StringBuilder mAddresses = new StringBuilder();
+ private StringBuilder mRoutes = new StringBuilder();
+
+ /**
+ * Set the name of this session. It will be displayed in system-managed
+ * dialogs and notifications. This is recommended not required.
+ */
+ public VpnBuilder setSession(String session) {
+ mConfig.session = session;
+ return this;
+ }
+
+ /**
+ * Set the {@link PendingIntent} to an activity for users to configure
+ * the VPN connection. If it is not set, the button to configure will
+ * not be shown in system-managed dialogs.
+ */
+ public VpnBuilder setConfigureIntent(PendingIntent intent) {
+ mConfig.configureIntent = intent;
+ return this;
+ }
+
+ /**
+ * Set the maximum transmission unit (MTU) of the VPN interface. If it
+ * is not set, the default value in the operating system will be used.
+ *
+ * @throws IllegalArgumentException if the value is not positive.
+ */
+ public VpnBuilder setMtu(int mtu) {
+ if (mtu <= 0) {
+ throw new IllegalArgumentException("Bad mtu");
+ }
+ mConfig.mtu = mtu;
+ return this;
+ }
+
+ /**
+ * Private method to validate address and prefixLength.
+ */
+ private static void check(InetAddress address, int prefixLength) {
+ if (address.isLoopbackAddress()) {
+ throw new IllegalArgumentException("Bad address");
+ }
+ if (address instanceof Inet4Address) {
+ if (prefixLength < 0 || prefixLength > 32) {
+ throw new IllegalArgumentException("Bad prefixLength");
+ }
+ } else if (address instanceof Inet6Address) {
+ if (prefixLength < 0 || prefixLength > 128) {
+ throw new IllegalArgumentException("Bad prefixLength");
+ }
+ } else {
+ throw new IllegalArgumentException("Unsupported family");
+ }
+ }
+
+ /**
+ * Convenience method to add a network address to the VPN interface
+ * using a numeric address string. See {@link InetAddress} for the
+ * definitions of numeric address formats.
+ *
+ * @throws IllegalArgumentException if the address is invalid.
+ * @see #addAddress(InetAddress, int)
+ */
+ public VpnBuilder addAddress(String address, int prefixLength) {
+ return addAddress(InetAddress.parseNumericAddress(address), prefixLength);
+ }
+
+ /**
+ * Add a network address to the VPN interface. Both IPv4 and IPv6
+ * addresses are supported. At least one address must be set before
+ * calling {@link #establish}.
+ *
+ * @throws IllegalArgumentException if the address is invalid.
+ */
+ public VpnBuilder addAddress(InetAddress address, int prefixLength) {
+ check(address, prefixLength);
+
+ if (address.isAnyLocalAddress()) {
+ throw new IllegalArgumentException("Bad address");
+ }
+
+ mAddresses.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
+ return this;
+ }
+
+ /**
+ * Convenience method to add a network route to the VPN interface
+ * using a numeric address string. See {@link InetAddress} for the
+ * definitions of numeric address formats.
+ *
+ * @see #addRoute(InetAddress, int)
+ * @throws IllegalArgumentException if the route is invalid.
+ */
+ public VpnBuilder addRoute(String address, int prefixLength) {
+ return addRoute(InetAddress.parseNumericAddress(address), prefixLength);
+ }
+
+ /**
+ * Add a network route to the VPN interface. Both IPv4 and IPv6
+ * routes are supported.
+ *
+ * @throws IllegalArgumentException if the route is invalid.
+ */
+ public VpnBuilder addRoute(InetAddress address, int prefixLength) {
+ check(address, prefixLength);
+
+ int offset = prefixLength / 8;
+ byte[] bytes = address.getAddress();
+ if (offset < bytes.length) {
+ if ((byte)(bytes[offset] << (prefixLength % 8)) != 0) {
+ throw new IllegalArgumentException("Bad address");
+ }
+ while (++offset < bytes.length) {
+ if (bytes[offset] != 0) {
+ throw new IllegalArgumentException("Bad address");
+ }
+ }
+ }
+
+ mRoutes.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
+ return this;
+ }
+
+ /**
+ * Convenience method to add a DNS server to the VPN connection
+ * using a numeric address string. See {@link InetAddress} for the
+ * definitions of numeric address formats.
+ *
+ * @throws IllegalArgumentException if the address is invalid.
+ * @see #addDnsServer(InetAddress)
+ */
+ public VpnBuilder addDnsServer(String address) {
+ return addDnsServer(InetAddress.parseNumericAddress(address));
+ }
+
+ /**
+ * Add a DNS server to the VPN connection. Both IPv4 and IPv6
+ * addresses are supported. If none is set, the DNS servers of
+ * the default network will be used.
+ *
+ * @throws IllegalArgumentException if the address is invalid.
+ */
+ public VpnBuilder addDnsServer(InetAddress address) {
+ if (address.isLoopbackAddress() || address.isAnyLocalAddress()) {
+ throw new IllegalArgumentException("Bad address");
+ }
+ if (mConfig.dnsServers == null) {
+ mConfig.dnsServers = new ArrayList<String>();
+ }
+ mConfig.dnsServers.add(address.getHostAddress());
+ return this;
+ }
+
+ /**
+ * Add a search domain to the DNS resolver.
+ */
+ public VpnBuilder addSearchDomain(String domain) {
+ if (mConfig.searchDomains == null) {
+ mConfig.searchDomains = new ArrayList<String>();
+ }
+ mConfig.searchDomains.add(domain);
+ return this;
+ }
+
+ /**
+ * Create a VPN interface using the parameters supplied to this builder.
+ * The interface works on IP packets, and a file descriptor is returned
+ * for the application to access them. Each read retrieves an outgoing
+ * packet which was routed to the interface. Each write injects an
+ * incoming packet just like it was received from the interface. The file
+ * descriptor is put into non-blocking mode by default to avoid blocking
+ * Java threads. To use the file descriptor completely in native space,
+ * see {@link ParcelFileDescriptor#detachFd()}. The application MUST
+ * close the file descriptor when the VPN connection is terminated. The
+ * VPN interface will be removed and the network will be restored by the
+ * framework automatically.
+ *
+ * <p>To avoid conflicts, there can be only one active VPN interface at
+ * the same time. Usually network parameters are never changed during the
+ * lifetime of a VPN connection. It is also common for an application to
+ * create a new file descriptor after closing the previous one. However,
+ * it is rare but not impossible to have two interfaces while performing a
+ * seamless handover. In this case, the old interface will be deactivated
+ * when the new one is configured successfully. Both file descriptors are
+ * valid but now outgoing packets will be routed to the new interface.
+ * Therefore, after draining the old file descriptor, the application MUST
+ * close it and start using the new file descriptor. If the new interface
+ * cannot be created, the existing interface and its file descriptor remain
+ * untouched.
+ *
+ * <p>An exception will be thrown if the interface cannot be created for
+ * any reason. However, this method returns {@code null} if the application
+ * is not prepared or is revoked by another application. This helps solve
+ * possible race conditions while handling {@link #ACTION_VPN_REVOKED}
+ * broadcasts.
+ *
+ * @return {@link ParcelFileDescriptor} of the VPN interface, or
+ * {@code null} if the application is not prepared.
+ * @throws IllegalArgumentException if a parameter is not accepted by the
+ * operating system.
+ * @throws IllegalStateException if a parameter cannot be applied by the
+ * operating system.
+ * @see #prepare
+ */
+ public ParcelFileDescriptor establish() {
+ mConfig.addresses = mAddresses.toString();
+ mConfig.routes = mRoutes.toString();
+
+ try {
+ return getService().establishVpn(mConfig);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Protect a socket from VPN connections. The socket will be bound to the
+ * current default network interface, so its traffic will not be forwarded
+ * through VPN. This method is useful if some connections need to be kept
+ * outside of VPN. For example, a VPN tunnel should protect itself if its
+ * destination is covered by VPN routes. Otherwise its outgoing packets
+ * will be sent back to the VPN interface and cause an infinite loop.
+ *
+ * <p>The socket is NOT closed by this method.
+ *
+ * @return {@code true} on success.
+ */
+ public static boolean protect(int socket) {
+ ParcelFileDescriptor dup = null;
+ try {
+ dup = ParcelFileDescriptor.fromFd(socket);
+ return getService().protectVpn(dup);
+ } catch (Exception e) {
+ return false;
+ } finally {
+ try {
+ dup.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * Protect a {@link Socket} from VPN connections.
+ *
+ * @return {@code true} on success.
+ * @see #protect(int)
+ */
+ public static boolean protect(Socket socket) {
+ return protect(socket.getFileDescriptor$().getInt$());
+ }
+
+ /**
+ * Protect a {@link DatagramSocket} from VPN connections.
+ *
+ * @return {@code true} on success.
+ * @see #protect(int)
+ */
+ public static boolean protect(DatagramSocket socket) {
+ return protect(socket.getFileDescriptor$().getInt$());
+ }
+}
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index cd39d5cc6dee..bc372447d63e 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -361,7 +361,8 @@ public class Handler {
/**
* Remove any pending posts of Runnable <var>r</var> with Object
- * <var>token</var> that are in the message queue.
+ * <var>token</var> that are in the message queue. If <var>token</var> is null,
+ * all callbacks will be removed.
*/
public final void removeCallbacks(Runnable r, Object token)
{
@@ -517,7 +518,8 @@ public class Handler {
/**
* Remove any pending posts of messages with code 'what' and whose obj is
- * 'object' that are in the message queue.
+ * 'object' that are in the message queue. If <var>token</var> is null,
+ * all messages will be removed.
*/
public final void removeMessages(int what, Object object) {
mQueue.removeMessages(this, what, object, true);
@@ -525,7 +527,8 @@ public class Handler {
/**
* Remove any pending posts of callbacks and sent messages whose
- * <var>obj</var> is <var>token</var>.
+ * <var>obj</var> is <var>token</var>. If <var>token</var> is null,
+ * all callbacks and messages will be removed.
*/
public final void removeCallbacksAndMessages(Object token) {
mQueue.removeCallbacksAndMessages(this, token);
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index c90de176896b..78c9010af8fd 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -563,6 +563,12 @@ public abstract class PreferenceActivity extends ListActivity implements
// Single pane, showing just a prefs fragment.
findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE);
mPrefsContainer.setVisibility(View.VISIBLE);
+ if (initialTitle != 0) {
+ CharSequence initialTitleStr = getText(initialTitle);
+ CharSequence initialShortTitleStr = initialShortTitle != 0
+ ? getText(initialShortTitle) : null;
+ showBreadCrumbs(initialTitleStr, initialShortTitleStr);
+ }
} else if (mHeaders.size() > 0) {
setListAdapter(new HeaderAdapter(this, mHeaders));
if (!mSinglePane) {
@@ -1093,6 +1099,10 @@ public abstract class PreferenceActivity extends ListActivity implements
} else {
getListView().clearChoices();
}
+ showBreadCrumbs(header);
+ }
+
+ void showBreadCrumbs(Header header) {
if (header != null) {
CharSequence title = header.getBreadCrumbTitle(getResources());
if (title == null) title = header.getTitle(getResources());
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index c2998916add4..4a719ec7b9a1 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1439,6 +1439,13 @@ public final class ContactsContract {
CONTENT_URI, "strequent");
/**
+ * The content:// style URI for showing frequently contacted person listing.
+ * @hide
+ */
+ public static final Uri CONTENT_FREQUENT_URI = Uri.withAppendedPath(
+ CONTENT_URI, "frequent");
+
+ /**
* The content:// style URI used for "type-to-filter" functionality on the
* {@link #CONTENT_STREQUENT_URI} URI. The filter string will be used to match
* various parts of the contact name. The filter argument should be passed
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cb87e94164bb..1cd46dedd2d2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -16,8 +16,6 @@
package android.provider;
-
-
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.SearchManager;
@@ -48,7 +46,6 @@ import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
-
/**
* The Settings provider contains global system-level device preferences.
*/
@@ -3737,6 +3734,15 @@ public final class Settings {
*/
public static final String VOICE_RECOGNITION_SERVICE = "voice_recognition_service";
+
+ /**
+ * The {@link ComponentName} string of the service to be used as the spell checker
+ * service which is one of the services managed by the text service manager.
+ *
+ * @hide
+ */
+ public static final String SPELL_CHECKER_SERVICE = "spell_checker_service";
+
/**
* What happens when the user presses the Power button while in-call
* and the screen is on.<br/>
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
new file mode 100644
index 000000000000..6ac99cab0ebf
--- /dev/null
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+import com.android.internal.textservice.ISpellCheckerService;
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.textservice.SuggestionsInfo;
+import android.view.textservice.TextInfo;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * SpellCheckerService provides an abstract base class for a spell checker.
+ * This class combines a service to the system with the spell checker service interface that
+ * spell checker must implement.
+ */
+public abstract class SpellCheckerService extends Service {
+ private static final String TAG = SpellCheckerService.class.getSimpleName();
+ public static final String SERVICE_INTERFACE = SpellCheckerService.class.getName();
+
+ private final SpellCheckerServiceBinder mBinder = new SpellCheckerServiceBinder(this);
+
+ /**
+ * Get suggestions for specified text in TextInfo.
+ * This function will run on the incoming IPC thread. So, this is not called on the main thread,
+ * but will be called in series on another thread.
+ * @param textInfo the text metadata
+ * @param suggestionsLimit the number of limit of suggestions returned
+ * @param locale the locale for getting suggestions
+ * @return SuggestionInfo which contains suggestions for textInfo
+ */
+ public abstract SuggestionsInfo getSuggestions(
+ TextInfo textInfo, int suggestionsLimit, String locale);
+
+ /**
+ * A batch process of onGetSuggestions.
+ * This function will run on the incoming IPC thread. So, this is not called on the main thread,
+ * but will be called in series on another thread.
+ * @param textInfos an array of the text metadata
+ * @param locale the locale for getting suggestions
+ * @param suggestionsLimit the number of limit of suggestions returned
+ * @param sequentialWords true if textInfos can be treated as sequential words.
+ * @return an array of SuggestionInfo of onGetSuggestions
+ */
+ public SuggestionsInfo[] getSuggestionsMultiple(
+ TextInfo[] textInfos, String locale, int suggestionsLimit, boolean sequentialWords) {
+ final int length = textInfos.length;
+ final SuggestionsInfo[] retval = new SuggestionsInfo[length];
+ for (int i = 0; i < length; ++i) {
+ retval[i] = getSuggestions(textInfos[i], suggestionsLimit, locale);
+ retval[i].setCookieAndSequence(textInfos[i].getCookie(), textInfos[i].getSequence());
+ }
+ return retval;
+ }
+
+ /**
+ * Request to abort all tasks executed in SpellChecker.
+ * This function will run on the incoming IPC thread. So, this is not called on the main thread,
+ * but will be called in series on another thread.
+ */
+ public void cancel() {}
+
+ /**
+ * Implement to return the implementation of the internal spell checker
+ * service interface. Subclasses should not override.
+ */
+ @Override
+ public final IBinder onBind(final Intent intent) {
+ return mBinder;
+ }
+
+ private static class SpellCheckerSessionImpl extends ISpellCheckerSession.Stub {
+ private final WeakReference<SpellCheckerService> mInternalServiceRef;
+ private final String mLocale;
+ private final ISpellCheckerSessionListener mListener;
+
+ public SpellCheckerSessionImpl(
+ SpellCheckerService service, String locale, ISpellCheckerSessionListener listener) {
+ mInternalServiceRef = new WeakReference<SpellCheckerService>(service);
+ mLocale = locale;
+ mListener = listener;
+ }
+
+ @Override
+ public void getSuggestionsMultiple(
+ TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
+ final SpellCheckerService service = mInternalServiceRef.get();
+ if (service == null) return;
+ try {
+ mListener.onGetSuggestions(
+ service.getSuggestionsMultiple(textInfos, mLocale,
+ suggestionsLimit, sequentialWords));
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void cancel() {
+ final SpellCheckerService service = mInternalServiceRef.get();
+ if (service == null) return;
+ service.cancel();
+ }
+ }
+
+ private static class SpellCheckerServiceBinder extends ISpellCheckerService.Stub {
+ private final WeakReference<SpellCheckerService> mInternalServiceRef;
+
+ public SpellCheckerServiceBinder(SpellCheckerService service) {
+ mInternalServiceRef = new WeakReference<SpellCheckerService>(service);
+ }
+
+ @Override
+ public ISpellCheckerSession getISpellCheckerSession(
+ String locale, ISpellCheckerSessionListener listener) {
+ final SpellCheckerService service = mInternalServiceRef.get();
+ if (service == null) return null;
+ return new SpellCheckerSessionImpl(service, locale, listener);
+ }
+ }
+}
diff --git a/core/java/android/service/textservice/SpellCheckerSession.java b/core/java/android/service/textservice/SpellCheckerSession.java
new file mode 100644
index 000000000000..a575220ef915
--- /dev/null
+++ b/core/java/android/service/textservice/SpellCheckerSession.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+import com.android.internal.textservice.ITextServicesManager;
+import com.android.internal.textservice.ITextServicesSessionListener;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.textservice.SuggestionsInfo;
+import android.view.textservice.TextInfo;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+/**
+ * The SpellCheckerSession interface provides the per client functionality of SpellCheckerService.
+ */
+public class SpellCheckerSession {
+ private static final String TAG = SpellCheckerSession.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ private static final int MSG_ON_GET_SUGGESTION_MULTIPLE = 1;
+
+ private final InternalListener mInternalListener;
+ private final ITextServicesManager mTextServicesManager;
+ private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl;
+
+ private boolean mIsUsed;
+ private SpellCheckerSessionListener mSpellCheckerSessionListener;
+
+ /** Handler that will execute the main tasks */
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ON_GET_SUGGESTION_MULTIPLE:
+ handleOnGetSuggestionsMultiple((SuggestionsInfo[]) msg.obj);
+ break;
+ }
+ }
+ };
+
+ /**
+ * Constructor
+ * @hide
+ */
+ public SpellCheckerSession(ITextServicesManager tsm, SpellCheckerSessionListener listener) {
+ if (listener == null || tsm == null) {
+ throw new NullPointerException();
+ }
+ mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(mHandler);
+ mInternalListener = new InternalListener();
+ mTextServicesManager = tsm;
+ mIsUsed = true;
+ mSpellCheckerSessionListener = listener;
+ }
+
+ /**
+ * @return true if the connection to a text service of this session is disconnected and not
+ * alive.
+ */
+ public boolean isSessionDisconnected() {
+ return mSpellCheckerSessionListenerImpl.isDisconnected();
+ }
+
+ /**
+ * Finish this session and allow TextServicesManagerService to disconnect the bound spell
+ * checker.
+ */
+ public void close() {
+ mIsUsed = false;
+ try {
+ mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl);
+ } catch (RemoteException e) {
+ // do nothing
+ }
+ }
+
+ /**
+ * Get candidate strings for a substring of the specified text.
+ * @param textInfo text metadata for a spell checker
+ * @param suggestionsLimit the number of limit of suggestions returned
+ */
+ public void getSuggestions(TextInfo textInfo, int suggestionsLimit) {
+ getSuggestions(new TextInfo[] {textInfo}, suggestionsLimit, false);
+ }
+
+ /**
+ * A batch process of getSuggestions
+ * @param textInfos an array of text metadata for a spell checker
+ * @param suggestionsLimit the number of limit of suggestions returned
+ * @param sequentialWords true if textInfos can be treated as sequential words.
+ */
+ public void getSuggestions(
+ TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
+ // TODO: Handle multiple words suggestions by using WordBreakIterator
+ mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
+ textInfos, suggestionsLimit, sequentialWords);
+ }
+
+ private void handleOnGetSuggestionsMultiple(SuggestionsInfo[] suggestionInfos) {
+ mSpellCheckerSessionListener.onGetSuggestions(suggestionInfos);
+ }
+
+ private static class SpellCheckerSessionListenerImpl extends ISpellCheckerSessionListener.Stub {
+ private static final int TASK_CANCEL = 1;
+ private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2;
+ private final Queue<SpellCheckerParams> mPendingTasks =
+ new LinkedList<SpellCheckerParams>();
+ private final Handler mHandler;
+
+ private boolean mOpened;
+ private ISpellCheckerSession mISpellCheckerSession;
+
+ public SpellCheckerSessionListenerImpl(Handler handler) {
+ mOpened = false;
+ mHandler = handler;
+ }
+
+ private static class SpellCheckerParams {
+ public final int mWhat;
+ public final TextInfo[] mTextInfos;
+ public final int mSuggestionsLimit;
+ public final boolean mSequentialWords;
+ public SpellCheckerParams(int what, TextInfo[] textInfos, int suggestionsLimit,
+ boolean sequentialWords) {
+ mWhat = what;
+ mTextInfos = textInfos;
+ mSuggestionsLimit = suggestionsLimit;
+ mSequentialWords = sequentialWords;
+ }
+ }
+
+ private void processTask(SpellCheckerParams scp) {
+ switch (scp.mWhat) {
+ case TASK_CANCEL:
+ processCancel();
+ break;
+ case TASK_GET_SUGGESTIONS_MULTIPLE:
+ processGetSuggestionsMultiple(scp);
+ break;
+ }
+ }
+
+ public synchronized void onServiceConnected(ISpellCheckerSession session) {
+ mISpellCheckerSession = session;
+ mOpened = true;
+ if (DBG)
+ Log.d(TAG, "onServiceConnected - Success");
+ while (!mPendingTasks.isEmpty()) {
+ processTask(mPendingTasks.poll());
+ }
+ }
+
+ public void getSuggestionsMultiple(
+ TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
+ processOrEnqueueTask(
+ new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE, textInfos,
+ suggestionsLimit, sequentialWords));
+ }
+
+ public boolean isDisconnected() {
+ return mOpened && mISpellCheckerSession == null;
+ }
+
+ public boolean checkOpenConnection() {
+ if (mISpellCheckerSession != null) {
+ return true;
+ }
+ Log.e(TAG, "not connected to the spellchecker service.");
+ return false;
+ }
+
+ private void processOrEnqueueTask(SpellCheckerParams scp) {
+ if (mISpellCheckerSession == null) {
+ mPendingTasks.offer(scp);
+ } else {
+ processTask(scp);
+ }
+ }
+
+ private void processCancel() {
+ if (!checkOpenConnection()) {
+ return;
+ }
+ try {
+ mISpellCheckerSession.cancel();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to cancel " + e);
+ }
+ }
+
+ private void processGetSuggestionsMultiple(SpellCheckerParams scp) {
+ if (!checkOpenConnection()) {
+ return;
+ }
+ try {
+ mISpellCheckerSession.getSuggestionsMultiple(
+ scp.mTextInfos, scp.mSuggestionsLimit, scp.mSequentialWords);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get suggestions " + e);
+ }
+ }
+
+ @Override
+ public void onGetSuggestions(SuggestionsInfo[] results) {
+ mHandler.sendMessage(Message.obtain(mHandler, MSG_ON_GET_SUGGESTION_MULTIPLE, results));
+ }
+ }
+
+ /**
+ * Callback for getting results from text services
+ */
+ public interface SpellCheckerSessionListener {
+ /**
+ * Callback for "getSuggestions"
+ * @param results an array of results of getSuggestions
+ */
+ public void onGetSuggestions(SuggestionsInfo[] results);
+ }
+
+ private class InternalListener extends ITextServicesSessionListener.Stub {
+ @Override
+ public void onServiceConnected(ISpellCheckerSession session) {
+ mSpellCheckerSessionListenerImpl.onServiceConnected(session);
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ if (mIsUsed) {
+ Log.e(TAG, "SpellCheckerSession was not finished properly." +
+ "You should call finishShession() when you finished to use a spell checker.");
+ close();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public ITextServicesSessionListener getTextServicesSessionListener() {
+ return mInternalListener;
+ }
+
+ /**
+ * @hide
+ */
+ public ISpellCheckerSessionListener getSpellCheckerSessionListener() {
+ return mSpellCheckerSessionListenerImpl;
+ }
+}
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index f1393721cb41..f2a86c969368 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -740,8 +740,8 @@ public final class JsonReader implements Closeable {
limit += total;
// if this is the first read, consume an optional byte order mark (BOM) if it exists
- if (bufferStartLine == 1 && bufferStartColumn == 1
- && limit > 0 && buffer[0] == '\ufeff') {
+ if (bufferStartLine == 1 && bufferStartColumn == 1
+ && limit > 0 && buffer[0] == '\ufeff') {
pos++;
bufferStartColumn--;
}
@@ -852,7 +852,7 @@ public final class JsonReader implements Closeable {
private boolean skipTo(String toFind) throws IOException {
outer:
- for (; pos + toFind.length() < limit || fillBuffer(toFind.length()); pos++) {
+ for (; pos + toFind.length() <= limit || fillBuffer(toFind.length()); pos++) {
for (int c = 0; c < toFind.length(); c++) {
if (buffer[pos + c] != toFind.charAt(c)) {
continue outer;
diff --git a/core/java/android/view/CollapsibleActionView.java b/core/java/android/view/CollapsibleActionView.java
new file mode 100644
index 000000000000..ab2365eb744c
--- /dev/null
+++ b/core/java/android/view/CollapsibleActionView.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 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;
+
+import android.view.MenuItem.OnActionExpandListener;
+
+/**
+ * When a {@link View} implements this interface it will receive callbacks
+ * when expanded or collapsed as an action view alongside the optional,
+ * app-specified callbacks to {@link OnActionExpandListener}.
+ *
+ * <p>See {@link MenuItem} for more information about action views.
+ * See {@link android.app.ActionBar} for more information about the action bar.
+ */
+public interface CollapsibleActionView {
+ /**
+ * Called when this view is expanded as an action view.
+ * See {@link MenuItem#expandActionView()}.
+ */
+ public void onActionViewExpanded();
+
+ /**
+ * Called when this view is collapsed as an action view.
+ * See {@link MenuItem#collapseActionView()}.
+ */
+ public void onActionViewCollapsed();
+}
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 4484d59a3ce4..f4c0249ab5a9 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -41,15 +41,6 @@ public abstract class DisplayList {
abstract void end();
/**
- * Indicates whether this display list can be replayed or not.
- *
- * @return True if the display list can be replayed, false otherwise.
- *
- * @see android.view.HardwareCanvas#drawDisplayList(DisplayList)
- */
- abstract boolean isReady();
-
- /**
* Invalidates the display list, indicating that it should be repopulated
* with new drawing commands prior to being used again. Calling this method
* causes calls to {@link #isValid()} to return <code>false</code>.
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 80244bbe9244..d22fa6e501ec 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -51,6 +51,7 @@ class GLES20Canvas extends HardwareCanvas {
// The native renderer will be destroyed when this object dies.
// DO NOT overwrite this reference once it is set.
+ @SuppressWarnings("unused")
private CanvasFinalizer mFinalizer;
private int mWidth;
@@ -97,12 +98,8 @@ class GLES20Canvas extends HardwareCanvas {
protected GLES20Canvas(boolean record, boolean translucent) {
mOpaque = !translucent;
- setupRenderer(record);
- }
-
- protected void setupRenderer(boolean record) {
if (record) {
- mRenderer = nGetDisplayListRenderer(mRenderer);
+ mRenderer = nCreateDisplayListRenderer();
} else {
mRenderer = nCreateRenderer();
}
@@ -114,43 +111,31 @@ class GLES20Canvas extends HardwareCanvas {
if (mRenderer == 0) {
throw new IllegalStateException("Could not create GLES20Canvas renderer");
} else {
- mFinalizer = CanvasFinalizer.getFinalizer(mFinalizer, mRenderer);
+ mFinalizer = new CanvasFinalizer(mRenderer);
}
}
+ protected void resetDisplayListRenderer() {
+ nResetDisplayListRenderer(mRenderer);
+ }
+
private static native int nCreateRenderer();
private static native int nCreateLayerRenderer(int layer);
- private static native int nGetDisplayListRenderer(int renderer);
+ private static native int nCreateDisplayListRenderer();
+ private static native void nResetDisplayListRenderer(int renderer);
private static native void nDestroyRenderer(int renderer);
- private static class CanvasFinalizer {
- int mRenderer;
-
- // Factory method returns new instance if old one is null, or old instance
- // otherwise, destroying native renderer along the way as necessary
- static CanvasFinalizer getFinalizer(CanvasFinalizer oldFinalizer, int renderer) {
- if (oldFinalizer == null) {
- return new CanvasFinalizer(renderer);
- }
- oldFinalizer.replaceNativeObject(renderer);
- return oldFinalizer;
- }
+ private static final class CanvasFinalizer {
+ private final int mRenderer;
- private CanvasFinalizer(int renderer) {
+ public CanvasFinalizer(int renderer) {
mRenderer = renderer;
}
- private void replaceNativeObject(int newRenderer) {
- if (mRenderer != 0 && newRenderer != mRenderer) {
- nDestroyRenderer(mRenderer);
- }
- mRenderer = newRenderer;
- }
-
@Override
protected void finalize() throws Throwable {
try {
- replaceNativeObject(0);
+ nDestroyRenderer(mRenderer);
} finally {
super.finalize();
}
@@ -322,11 +307,11 @@ class GLES20Canvas extends HardwareCanvas {
// Display list
///////////////////////////////////////////////////////////////////////////
- int getDisplayList() {
- return nGetDisplayList(mRenderer);
+ int getDisplayList(int displayList) {
+ return nGetDisplayList(mRenderer, displayList);
}
- private static native int nGetDisplayList(int renderer);
+ private static native int nGetDisplayList(int renderer, int displayList);
static void destroyDisplayList(int displayList) {
nDestroyDisplayList(displayList);
@@ -337,7 +322,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
return nDrawDisplayList(mRenderer,
- ((GLES20DisplayList) displayList).mNativeDisplayList, width, height, dirty);
+ ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty);
}
private static native boolean nDrawDisplayList(int renderer, int displayList,
@@ -345,7 +330,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
void outputDisplayList(DisplayList displayList) {
- nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
+ nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
}
private static native void nOutputDisplayList(int renderer, int displayList);
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index aeff31f8a193..9e649cea63dc 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -16,52 +16,50 @@
package android.view;
-import java.lang.ref.WeakReference;
+import android.graphics.Bitmap;
+
+import java.util.ArrayList;
/**
* An implementation of display list for OpenGL ES 2.0.
*/
class GLES20DisplayList extends DisplayList {
- private GLES20Canvas mCanvas;
-
- private boolean mStarted = false;
- private boolean mRecorded = false;
- private boolean mValid = false;
+ // These lists ensure that any Bitmaps recorded by a DisplayList are kept alive as long
+ // as the DisplayList is alive. The Bitmaps are populated by the GLES20RecordingCanvas.
+ final ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(5);
- int mNativeDisplayList;
- WeakReference<View> hostView;
+ private GLES20RecordingCanvas mCanvas;
+ private boolean mValid;
// The native display list will be destroyed when this object dies.
// DO NOT overwrite this reference once it is set.
- @SuppressWarnings("unused")
private DisplayListFinalizer mFinalizer;
- public GLES20DisplayList(View view) {
- hostView = new WeakReference<View>(view);
+ int getNativeDisplayList() {
+ if (!mValid || mFinalizer == null) {
+ throw new IllegalStateException("The display list is not valid.");
+ }
+ return mFinalizer.mNativeDisplayList;
}
@Override
HardwareCanvas start() {
- if (mStarted) {
- throw new IllegalStateException("Recording has already started");
- }
-
if (mCanvas != null) {
- ((GLES20RecordingCanvas) mCanvas).reset();
- } else {
- mCanvas = new GLES20RecordingCanvas(true);
+ throw new IllegalStateException("Recording has already started");
}
- mStarted = true;
- mRecorded = false;
- mValid = true;
+ mValid = false;
+ mCanvas = GLES20RecordingCanvas.obtain(this);
+ mCanvas.start();
return mCanvas;
}
@Override
void invalidate() {
- mStarted = false;
- mRecorded = false;
+ if (mCanvas != null) {
+ mCanvas.recycle();
+ mCanvas = null;
+ }
mValid = false;
}
@@ -73,48 +71,28 @@ class GLES20DisplayList extends DisplayList {
@Override
void end() {
if (mCanvas != null) {
- mStarted = false;
- mRecorded = true;
-
- mNativeDisplayList = mCanvas.getDisplayList();
- mFinalizer = DisplayListFinalizer.getFinalizer(mFinalizer, mNativeDisplayList);
+ if (mFinalizer != null) {
+ mCanvas.end(mFinalizer.mNativeDisplayList);
+ } else {
+ mFinalizer = new DisplayListFinalizer(mCanvas.end(0));
+ }
+ mCanvas.recycle();
+ mCanvas = null;
+ mValid = true;
}
}
- @Override
- boolean isReady() {
- return !mStarted && mRecorded;
- }
-
private static class DisplayListFinalizer {
- int mNativeDisplayList;
-
- // Factory method returns new instance if old one is null, or old instance
- // otherwise, destroying native display list along the way as necessary
- static DisplayListFinalizer getFinalizer(DisplayListFinalizer oldFinalizer,
- int nativeDisplayList) {
- if (oldFinalizer == null) {
- return new DisplayListFinalizer(nativeDisplayList);
- }
- oldFinalizer.replaceNativeObject(nativeDisplayList);
- return oldFinalizer;
- }
+ final int mNativeDisplayList;
- private DisplayListFinalizer(int nativeDisplayList) {
+ public DisplayListFinalizer(int nativeDisplayList) {
mNativeDisplayList = nativeDisplayList;
}
- private void replaceNativeObject(int newNativeDisplayList) {
- if (mNativeDisplayList != 0 && mNativeDisplayList != newNativeDisplayList) {
- GLES20Canvas.destroyDisplayList(mNativeDisplayList);
- }
- mNativeDisplayList = newNativeDisplayList;
- }
-
@Override
protected void finalize() throws Throwable {
try {
- replaceNativeObject(0);
+ GLES20Canvas.destroyDisplayList(mNativeDisplayList);
} finally {
super.finalize();
}
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index ec94fe70ae91..078222be6fe9 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -24,8 +24,10 @@ import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
-
-import java.util.ArrayList;
+import android.util.Pool;
+import android.util.Poolable;
+import android.util.PoolableManager;
+import android.util.Pools;
/**
* An implementation of a GL canvas that records drawing operations.
@@ -33,62 +35,94 @@ import java.util.ArrayList;
* Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
* the DisplayList is still holding a native reference to the memory.
*/
-class GLES20RecordingCanvas extends GLES20Canvas {
- // These lists ensure that any Bitmaps recorded by a DisplayList are kept alive as long
- // as the DisplayList is alive.
- @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"})
- private final ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(5);
+class GLES20RecordingCanvas extends GLES20Canvas implements Poolable<GLES20RecordingCanvas> {
+ // The recording canvas pool should be large enough to handle a deeply nested
+ // view hierarchy because display lists are generated recursively.
+ private static final int POOL_LIMIT = 50;
+
+ private static final Pool<GLES20RecordingCanvas> sPool = Pools.synchronizedPool(
+ Pools.finitePool(new PoolableManager<GLES20RecordingCanvas>() {
+ public GLES20RecordingCanvas newInstance() {
+ return new GLES20RecordingCanvas();
+ }
+ @Override
+ public void onAcquired(GLES20RecordingCanvas element) {
+ }
+ @Override
+ public void onReleased(GLES20RecordingCanvas element) {
+ }
+ }, POOL_LIMIT));
+
+ private GLES20RecordingCanvas mNextPoolable;
+ private boolean mIsPooled;
+
+ private GLES20DisplayList mDisplayList;
- GLES20RecordingCanvas(boolean translucent) {
- super(true, translucent);
+ private GLES20RecordingCanvas() {
+ super(true /*record*/, true /*translucent*/);
+ }
+
+ static GLES20RecordingCanvas obtain(GLES20DisplayList displayList) {
+ GLES20RecordingCanvas canvas = sPool.acquire();
+ canvas.mDisplayList = displayList;
+ return canvas;
+ }
+
+ void recycle() {
+ mDisplayList = null;
+ resetDisplayListRenderer();
+ sPool.release(this);
+ }
+
+ void start() {
+ mDisplayList.mBitmaps.clear();
+ }
+
+ int end(int nativeDisplayList) {
+ return getDisplayList(nativeDisplayList);
}
private void recordShaderBitmap(Paint paint) {
if (paint != null) {
final Shader shader = paint.getShader();
if (shader instanceof BitmapShader) {
- mBitmaps.add(((BitmapShader) shader).mBitmap);
+ mDisplayList.mBitmaps.add(((BitmapShader) shader).mBitmap);
}
}
}
- void reset() {
- mBitmaps.clear();
- setupRenderer(true);
- }
-
@Override
public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
super.drawPatch(bitmap, chunks, dst, paint);
- mBitmaps.add(bitmap);
+ mDisplayList.mBitmaps.add(bitmap);
// Shaders in the Paint are ignored when drawing a Bitmap
}
@Override
public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
super.drawBitmap(bitmap, left, top, paint);
- mBitmaps.add(bitmap);
+ mDisplayList.mBitmaps.add(bitmap);
// Shaders in the Paint are ignored when drawing a Bitmap
}
@Override
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
super.drawBitmap(bitmap, matrix, paint);
- mBitmaps.add(bitmap);
+ mDisplayList.mBitmaps.add(bitmap);
// Shaders in the Paint are ignored when drawing a Bitmap
}
@Override
public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
super.drawBitmap(bitmap, src, dst, paint);
- mBitmaps.add(bitmap);
+ mDisplayList.mBitmaps.add(bitmap);
// Shaders in the Paint are ignored when drawing a Bitmap
}
@Override
public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
super.drawBitmap(bitmap, src, dst, paint);
- mBitmaps.add(bitmap);
+ mDisplayList.mBitmaps.add(bitmap);
// Shaders in the Paint are ignored when drawing a Bitmap
}
@@ -111,7 +145,7 @@ class GLES20RecordingCanvas extends GLES20Canvas {
int vertOffset, int[] colors, int colorOffset, Paint paint) {
super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset,
paint);
- mBitmaps.add(bitmap);
+ mDisplayList.mBitmaps.add(bitmap);
// Shaders in the Paint are ignored when drawing a Bitmap
}
@@ -270,4 +304,24 @@ class GLES20RecordingCanvas extends GLES20Canvas {
colorOffset, indices, indexOffset, indexCount, paint);
recordShaderBitmap(paint);
}
+
+ @Override
+ public GLES20RecordingCanvas getNextPoolable() {
+ return mNextPoolable;
+ }
+
+ @Override
+ public void setNextPoolable(GLES20RecordingCanvas element) {
+ mNextPoolable = element;
+ }
+
+ @Override
+ public boolean isPooled() {
+ return mIsPooled;
+ }
+
+ @Override
+ public void setPooled(boolean isPooled) {
+ mIsPooled = isPooled;
+ }
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index b865b5007200..503b54bd437d 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -189,7 +189,7 @@ public abstract class HardwareRenderer {
*
* @return A new display list.
*/
- abstract DisplayList createDisplayList(View v);
+ abstract DisplayList createDisplayList();
/**
* Creates a new hardware layer. A hardware layer built by calling this
@@ -852,8 +852,8 @@ public abstract class HardwareRenderer {
}
@Override
- DisplayList createDisplayList(View v) {
- return new GLES20DisplayList(v);
+ DisplayList createDisplayList() {
+ return new GLES20DisplayList();
}
@Override
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 930eb25412f4..ecb391d12bf1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9833,7 +9833,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
// we copy in child display lists into ours in drawChild()
mRecreateDisplayList = true;
if (mDisplayList == null) {
- mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(this);
+ mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList();
// If we're creating a new display list, make sure our parent gets invalidated
// since they will need to recreate their display list to account for this
// new child display list.
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 5f61cbbf2d05..4acf48c6b316 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -25,6 +25,7 @@ import android.os.Debug;
import android.os.Environment;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.DisplayMetrics;
@@ -50,6 +51,9 @@ import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
@@ -453,24 +457,33 @@ public class ViewDebug {
}
private static class LooperProfiler implements Looper.Profiler, Printer {
- private static final int LOOPER_PROFILER_VERSION = 1;
-
private static final String LOG_TAG = "LooperProfiler";
+ private static final int TRACE_VERSION_NUMBER = 3;
+ private static final int ACTION_EXIT_METHOD = 0x1;
+ private static final int HEADER_SIZE = 32;
+ private static final String HEADER_MAGIC = "SLOW";
+ private static final short HEADER_RECORD_SIZE = (short) 14;
+
private final long mTraceWallStart;
private final long mTraceThreadStart;
private final ArrayList<Entry> mTraces = new ArrayList<Entry>(512);
- private final HashMap<String, Short> mTraceNames = new HashMap<String, Short>(32);
- private short mTraceId = 0;
+ private final HashMap<String, Integer> mTraceNames = new HashMap<String, Integer>(32);
+ private int mTraceId = 0;
private final String mPath;
- private final FileDescriptor mFileDescriptor;
+ private ParcelFileDescriptor mFileDescriptor;
LooperProfiler(String path, FileDescriptor fileDescriptor) {
mPath = path;
- mFileDescriptor = fileDescriptor;
+ try {
+ mFileDescriptor = ParcelFileDescriptor.dup(fileDescriptor);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
+ throw new RuntimeException(e);
+ }
mTraceWallStart = SystemClock.currentTimeMicro();
mTraceThreadStart = SystemClock.currentThreadTimeMicro();
}
@@ -493,11 +506,11 @@ public class ViewDebug {
mTraces.add(entry);
}
- private short getTraceId(Message message) {
+ private int getTraceId(Message message) {
String name = message.getTarget().getMessageName(message);
- Short traceId = mTraceNames.get(name);
+ Integer traceId = mTraceNames.get(name);
if (traceId == null) {
- traceId = mTraceId++;
+ traceId = mTraceId++ << 4;
mTraceNames.put(name, traceId);
}
return traceId;
@@ -514,51 +527,131 @@ public class ViewDebug {
}
private void saveTraces() {
- FileOutputStream fos = new FileOutputStream(mFileDescriptor);
+ FileOutputStream fos = new FileOutputStream(mFileDescriptor.getFileDescriptor());
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
try {
- out.writeInt(LOOPER_PROFILER_VERSION);
- out.writeLong(mTraceWallStart);
- out.writeLong(mTraceThreadStart);
-
- out.writeInt(mTraceNames.size());
- for (Map.Entry<String, Short> entry : mTraceNames.entrySet()) {
- saveTraceName(entry.getKey(), entry.getValue(), out);
- }
+ writeHeader(out, mTraceWallStart, mTraceNames, mTraces);
+ out.flush();
- out.writeInt(mTraces.size());
- for (Entry entry : mTraces) {
- saveTrace(entry, out);
- }
+ writeTraces(fos, out.size(), mTraceWallStart, mTraceThreadStart, mTraces);
Log.d(LOG_TAG, "Looper traces ready: " + mPath);
} catch (IOException e) {
- Log.e(LOG_TAG, "Could not write trace file: ", e);
+ Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
} finally {
try {
out.close();
} catch (IOException e) {
- // Ignore
+ Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
+ }
+ try {
+ mFileDescriptor.close();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
}
}
}
-
- private void saveTraceName(String name, short id, DataOutputStream out) throws IOException {
- out.writeShort(id);
- out.writeUTF(name);
+
+ private static void writeTraces(FileOutputStream out, long offset, long wallStart,
+ long threadStart, ArrayList<Entry> entries) throws IOException {
+
+ FileChannel channel = out.getChannel();
+
+ // Header
+ ByteBuffer buffer = ByteBuffer.allocateDirect(HEADER_SIZE);
+ buffer.put(HEADER_MAGIC.getBytes());
+ buffer = buffer.order(ByteOrder.LITTLE_ENDIAN);
+ buffer.putShort((short) TRACE_VERSION_NUMBER); // version
+ buffer.putShort((short) HEADER_SIZE); // offset to data
+ buffer.putLong(wallStart); // start time in usec
+ buffer.putShort(HEADER_RECORD_SIZE); // size of a record in bytes
+ // padding to 32 bytes
+ for (int i = 0; i < HEADER_SIZE - 18; i++) {
+ buffer.put((byte) 0);
+ }
+
+ buffer.flip();
+ channel.position(offset).write(buffer);
+
+ buffer = ByteBuffer.allocateDirect(14).order(ByteOrder.LITTLE_ENDIAN);
+ for (Entry entry : entries) {
+ buffer.putShort((short) 1); // we simulate only one thread
+ buffer.putInt(entry.traceId); // entering method
+ buffer.putInt((int) (entry.threadStart - threadStart));
+ buffer.putInt((int) (entry.wallStart - wallStart));
+
+ buffer.flip();
+ channel.write(buffer);
+ buffer.clear();
+
+ buffer.putShort((short) 1);
+ buffer.putInt(entry.traceId | ACTION_EXIT_METHOD); // exiting method
+ buffer.putInt((int) (entry.threadStart + entry.threadTime - threadStart));
+ buffer.putInt((int) (entry.wallStart + entry.wallTime - wallStart));
+
+ buffer.flip();
+ channel.write(buffer);
+ buffer.clear();
+ }
+
+ channel.close();
}
+
+ private static void writeHeader(DataOutputStream out, long start,
+ HashMap<String, Integer> names, ArrayList<Entry> entries) throws IOException {
+
+ Entry last = entries.get(entries.size() - 1);
+ long wallTotal = (last.wallStart + last.wallTime) - start;
+
+ startSection("version", out);
+ addValue(null, Integer.toString(TRACE_VERSION_NUMBER), out);
+ addValue("data-file-overflow", "false", out);
+ addValue("clock", "dual", out);
+ addValue("elapsed-time-usec", Long.toString(wallTotal), out);
+ addValue("num-method-calls", Integer.toString(entries.size()), out);
+ addValue("clock-call-overhead-nsec", "1", out);
+ addValue("vm", "dalvik", out);
+
+ startSection("threads", out);
+ addThreadId(1, "main", out);
+
+ startSection("methods", out);
+ addMethods(names, out);
+
+ startSection("end", out);
+ }
+
+ private static void addMethods(HashMap<String, Integer> names, DataOutputStream out)
+ throws IOException {
+
+ for (Map.Entry<String, Integer> name : names.entrySet()) {
+ out.writeBytes(String.format("0x%08x\tEventQueue\t%s\t()V\tLooper\t-2\n",
+ name.getValue(), name.getKey()));
+ }
+ }
+
+ private static void addThreadId(int id, String name, DataOutputStream out)
+ throws IOException {
- private void saveTrace(Entry entry, DataOutputStream out) throws IOException {
- out.writeShort(entry.traceId);
- out.writeLong(entry.wallStart);
- out.writeLong(entry.wallTime);
- out.writeLong(entry.threadStart);
- out.writeLong(entry.threadTime);
+ out.writeBytes(Integer.toString(id) + '\t' + name + '\n');
+ }
+
+ private static void addValue(String name, String value, DataOutputStream out)
+ throws IOException {
+
+ if (name != null) {
+ out.writeBytes(name + "=");
+ }
+ out.writeBytes(value + '\n');
+ }
+
+ private static void startSection(String name, DataOutputStream out) throws IOException {
+ out.writeBytes("*" + name + '\n');
}
static class Entry {
- short traceId;
+ int traceId;
long wallStart;
long wallTime;
long threadStart;
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.aidl b/core/java/android/view/textservice/SpellCheckerInfo.aidl
new file mode 100644
index 000000000000..eb5dfcc01c88
--- /dev/null
+++ b/core/java/android/view/textservice/SpellCheckerInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+parcelable SpellCheckerInfo;
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
new file mode 100644
index 000000000000..1205adfaceb3
--- /dev/null
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class is used to specify meta information of an spell checker.
+ */
+public final class SpellCheckerInfo implements Parcelable {
+ private final ResolveInfo mService;
+ private final String mId;
+
+ /**
+ * Constructor.
+ * @hide
+ */
+ public SpellCheckerInfo(Context context, ResolveInfo service) {
+ mService = service;
+ ServiceInfo si = service.serviceInfo;
+ mId = new ComponentName(si.packageName, si.name).flattenToShortString();
+ }
+
+ /**
+ * Constructor.
+ * @hide
+ */
+ public SpellCheckerInfo(Parcel source) {
+ mId = source.readString();
+ mService = ResolveInfo.CREATOR.createFromParcel(source);
+ }
+
+ /**
+ * Return a unique ID for this spell checker. The ID is generated from
+ * the package and class name implementing the method.
+ */
+ public String getId() {
+ return mId;
+ }
+
+
+ /**
+ * Return the component of the service that implements.
+ */
+ public ComponentName getComponent() {
+ return new ComponentName(
+ mService.serviceInfo.packageName, mService.serviceInfo.name);
+ }
+
+ /**
+ * Return the .apk package that implements this input method.
+ */
+ public String getPackageName() {
+ return mService.serviceInfo.packageName;
+ }
+
+ /**
+ * Used to package this object into a {@link Parcel}.
+ *
+ * @param dest The {@link Parcel} to be written.
+ * @param flags The flags used for parceling.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mId);
+ mService.writeToParcel(dest, flags);
+ }
+
+
+ /**
+ * Used to make this class parcelable.
+ */
+ public static final Parcelable.Creator<SpellCheckerInfo> CREATOR
+ = new Parcelable.Creator<SpellCheckerInfo>() {
+ @Override
+ public SpellCheckerInfo createFromParcel(Parcel source) {
+ return new SpellCheckerInfo(source);
+ }
+
+ @Override
+ public SpellCheckerInfo[] newArray(int size) {
+ return new SpellCheckerInfo[size];
+ }
+ };
+
+ /**
+ * Used to make this class parcelable.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/view/textservice/SuggestionsInfo.aidl b/core/java/android/view/textservice/SuggestionsInfo.aidl
new file mode 100644
index 000000000000..66e20d24ce1c
--- /dev/null
+++ b/core/java/android/view/textservice/SuggestionsInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+parcelable SuggestionsInfo;
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
new file mode 100644
index 000000000000..b0ccbea7d91a
--- /dev/null
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains a metadata of suggestions from the text service
+ */
+public final class SuggestionsInfo implements Parcelable {
+ /**
+ * Flag of the attributes of the suggestions that can be obtained by
+ * {@link #getSuggestionsAttributes}: this tells that the requested word was found
+ * in the dictionary in the text service.
+ */
+ public static final int RESULT_ATTR_IN_THE_DICTIONARY = 0x0001;
+ /** Flag of the attributes of the suggestions that can be obtained by
+ * {@link #getSuggestionsAttributes}: this tells that there are one or more suggestions
+ * available for the requested word. This doesn't necessarily mean that the suggestions
+ * are actually in this SuggestionsInfo. For instance, the caller could have been asked to
+ * limit the maximum number of suggestions returned.
+ */
+ public static final int RESULT_ATTR_SUGGESTIONS_AVAILABLE = 0x0002;
+ /**
+ * Flag of the attributes of the suggestions that can be obtained by
+ * {@link #getSuggestionsAttributes}: this tells that the text service thinks the requested
+ * word looks a typo.
+ */
+ public static final int RESULT_ATTR_LOOKS_TYPO = 0x0004;
+ private final int mSuggestionsAttributes;
+ private final String[] mSuggestions;
+ private int mCookie;
+ private int mSequence;
+
+ /**
+ * Constructor.
+ * @param suggestionsAttributes from the text service
+ * @param suggestions from the text service
+ */
+ public SuggestionsInfo(int suggestionsAttributes, String[] suggestions) {
+ if (suggestions == null) {
+ throw new NullPointerException();
+ }
+ mSuggestionsAttributes = suggestionsAttributes;
+ mSuggestions = suggestions;
+ mCookie = 0;
+ mSequence = 0;
+ }
+
+ /**
+ * Constructor.
+ * @param suggestionsAttributes from the text service
+ * @param suggestions from the text service
+ * @param cookie the cookie of the input TextInfo
+ * @param sequence the cookie of the input TextInfo
+ */
+ public SuggestionsInfo(
+ int suggestionsAttributes, String[] suggestions, int cookie, int sequence) {
+ if (suggestions == null) {
+ throw new NullPointerException();
+ }
+ mSuggestionsAttributes = suggestionsAttributes;
+ mSuggestions = suggestions;
+ mCookie = cookie;
+ mSequence = sequence;
+ }
+
+ public SuggestionsInfo(Parcel source) {
+ mSuggestionsAttributes = source.readInt();
+ mSuggestions = source.readStringArray();
+ mCookie = source.readInt();
+ mSequence = source.readInt();
+ }
+
+ /**
+ * Used to package this object into a {@link Parcel}.
+ *
+ * @param dest The {@link Parcel} to be written.
+ * @param flags The flags used for parceling.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mSuggestionsAttributes);
+ dest.writeStringArray(mSuggestions);
+ dest.writeInt(mCookie);
+ dest.writeInt(mSequence);
+ }
+
+ /**
+ * Set the cookie and the sequence of SuggestionsInfo which are set to TextInfo from a client
+ * application
+ * @param cookie the cookie of an input TextInfo
+ * @param sequence the cookie of an input TextInfo
+ */
+ public void setCookieAndSequence(int cookie, int sequence) {
+ mCookie = cookie;
+ mSequence = sequence;
+ }
+
+ /**
+ * @return the cookie which may be set by a client application
+ */
+ public int getCookie() {
+ return mCookie;
+ }
+
+ /**
+ * @return the sequence which may be set by a client application
+ */
+ public int getSequence() {
+ return mSequence;
+ }
+
+ /**
+ * @return the attributes of suggestions. This includes whether the spell checker has the word
+ * in its dictionary or not and whether the spell checker has confident suggestions for the
+ * word or not.
+ */
+ public int getSuggestionsAttributes() {
+ return mSuggestionsAttributes;
+ }
+
+ /**
+ * @return the count of suggestions
+ */
+ public int getSuggestionsCount() {
+ return mSuggestions.length;
+ }
+
+ /**
+ * @param i the id of suggestions
+ * @return the suggestion at the specified id
+ */
+ public String getSuggestionAt(int i) {
+ return mSuggestions[i];
+ }
+
+ /**
+ * Used to make this class parcelable.
+ */
+ public static final Parcelable.Creator<SuggestionsInfo> CREATOR
+ = new Parcelable.Creator<SuggestionsInfo>() {
+ @Override
+ public SuggestionsInfo createFromParcel(Parcel source) {
+ return new SuggestionsInfo(source);
+ }
+
+ @Override
+ public SuggestionsInfo[] newArray(int size) {
+ return new SuggestionsInfo[size];
+ }
+ };
+
+ /**
+ * Used to make this class parcelable.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/view/textservice/TextInfo.aidl b/core/java/android/view/textservice/TextInfo.aidl
new file mode 100644
index 000000000000..d231d7638a75
--- /dev/null
+++ b/core/java/android/view/textservice/TextInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+parcelable TextInfo;
diff --git a/core/java/android/view/textservice/TextInfo.java b/core/java/android/view/textservice/TextInfo.java
new file mode 100644
index 000000000000..b534eb0be607
--- /dev/null
+++ b/core/java/android/view/textservice/TextInfo.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * This class contains a metadata of the input of TextService
+ */
+public final class TextInfo implements Parcelable {
+ private final String mText;
+ private final int mCookie;
+ private final int mSequence;
+
+ /**
+ * Constructor.
+ * @param text the text which will be input to TextService
+ */
+ public TextInfo(String text) {
+ this(text, 0, 0);
+ }
+
+ /**
+ * Constructor.
+ * @param text the text which will be input to TextService
+ * @param cookie the cookie for this TextInfo
+ * @param sequence the sequence number for this TextInfo
+ */
+ public TextInfo(String text, int cookie, int sequence) {
+ if (TextUtils.isEmpty(text)) {
+ throw new IllegalArgumentException(text);
+ }
+ mText = text;
+ mCookie = cookie;
+ mSequence = sequence;
+ }
+
+ public TextInfo(Parcel source) {
+ mText = source.readString();
+ mCookie = source.readInt();
+ mSequence = source.readInt();
+ }
+
+ /**
+ * Used to package this object into a {@link Parcel}.
+ *
+ * @param dest The {@link Parcel} to be written.
+ * @param flags The flags used for parceling.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mText);
+ dest.writeInt(mCookie);
+ dest.writeInt(mSequence);
+ }
+
+ /**
+ * @return the text which is an input of a text service
+ */
+ public String getText() {
+ return mText;
+ }
+
+ /**
+ * @return the cookie of TextInfo
+ */
+ public int getCookie() {
+ return mCookie;
+ }
+
+ /**
+ * @return the sequence of TextInfo
+ */
+ public int getSequence() {
+ return mSequence;
+ }
+
+ /**
+ * Used to make this class parcelable.
+ */
+ public static final Parcelable.Creator<TextInfo> CREATOR
+ = new Parcelable.Creator<TextInfo>() {
+ @Override
+ public TextInfo createFromParcel(Parcel source) {
+ return new TextInfo(source);
+ }
+
+ @Override
+ public TextInfo[] newArray(int size) {
+ return new TextInfo[size];
+ }
+ };
+
+ /**
+ * Used to make this class parcelable.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
new file mode 100644
index 000000000000..6fa7e4ddf9cd
--- /dev/null
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+import com.android.internal.textservice.ITextServicesManager;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.view.textservice.SpellCheckerInfo;
+import android.service.textservice.SpellCheckerSession;
+import android.service.textservice.SpellCheckerSession.SpellCheckerSessionListener;
+
+import java.util.Locale;
+
+/**
+ * System API to the overall text services, which arbitrates interaction between applications
+ * and text services. You can retrieve an instance of this interface with
+ * {@link Context#getSystemService(String) Context.getSystemService()}.
+ *
+ * The user can change the current text services in Settings. And also applications can specify
+ * the target text services.
+ */
+public final class TextServicesManager {
+ private static final String TAG = TextServicesManager.class.getSimpleName();
+
+ private static TextServicesManager sInstance;
+ private static ITextServicesManager sService;
+
+ private TextServicesManager() {
+ if (sService == null) {
+ IBinder b = ServiceManager.getService(Context.TEXT_SERVICES_MANAGER_SERVICE);
+ sService = ITextServicesManager.Stub.asInterface(b);
+ }
+ }
+
+ /**
+ * Retrieve the global TextServicesManager instance, creating it if it doesn't already exist.
+ * @hide
+ */
+ public static TextServicesManager getInstance() {
+ synchronized (TextServicesManager.class) {
+ if (sInstance != null) {
+ return sInstance;
+ }
+ sInstance = new TextServicesManager();
+ }
+ return sInstance;
+ }
+
+
+ /**
+ * Get the current spell checker service info for the specified locale.
+ * @param locale locale of a spell checker
+ * @return SpellCheckerInfo for the specified locale.
+ */
+ // TODO: Add a method to get enabled spell checkers.
+ public SpellCheckerInfo getCurrentSpellChecker(Locale locale) {
+ if (locale == null) {
+ throw new NullPointerException("locale is null");
+ }
+ try {
+ return sService.getCurrentSpellChecker(locale.toString());
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Get a spell checker session for a specified spell checker
+ * @param info SpellCheckerInfo of the spell checker
+ * @param locale the locale for the spell checker
+ * @param listener a spell checker session lister for getting results from a spell checker.
+ * @return the spell checker session of the spell checker
+ */
+ public SpellCheckerSession newSpellCheckerSession(
+ SpellCheckerInfo info, Locale locale, SpellCheckerSessionListener listener) {
+ if (info == null || locale == null || listener == null) {
+ throw new NullPointerException();
+ }
+ final SpellCheckerSession session = new SpellCheckerSession(sService, listener);
+ try {
+ sService.getSpellCheckerService(
+ info, locale.toString(), session.getTextServicesSessionListener(),
+ session.getSpellCheckerSessionListener());
+ } catch (RemoteException e) {
+ return null;
+ }
+ return session;
+ }
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 8f8c1d069b9d..b7c1687debef 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4638,9 +4638,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
childrenTop += getVerticalFadingEdgeLength();
}
}
- // Don't ever focus a disabled item.
- if (!mAdapter.isEnabled(i)) continue;
-
if (top >= childrenTop) {
// Found a view whose top is fully visisble
selectedPos = firstPosition + i;
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerService.aidl b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
new file mode 100644
index 000000000000..ff0049276bce
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+
+/**
+ * Public interface to the global spell checker.
+ * @hide
+ */
+interface ISpellCheckerService {
+ ISpellCheckerSession getISpellCheckerSession(
+ String locale, ISpellCheckerSessionListener listener);
+}
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
new file mode 100644
index 000000000000..79e43510c00a
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.textservice;
+
+import android.view.textservice.TextInfo;
+
+/**
+ * @hide
+ */
+oneway interface ISpellCheckerSession {
+ void getSuggestionsMultiple(
+ in TextInfo[] textInfos, int suggestionsLimit, boolean multipleWords);
+ void cancel();
+}
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl
new file mode 100644
index 000000000000..796b06eb06d6
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.textservice;
+
+import android.view.textservice.SuggestionsInfo;
+
+/**
+ * @hide
+ */
+oneway interface ISpellCheckerSessionListener {
+ void onGetSuggestions(in SuggestionsInfo[] results);
+}
diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
new file mode 100644
index 000000000000..ad0c1ff3f816
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+import com.android.internal.textservice.ITextServicesSessionListener;
+
+import android.content.ComponentName;
+import android.view.textservice.SpellCheckerInfo;
+
+/**
+ * Interface to the text service manager.
+ * @hide
+ */
+interface ITextServicesManager {
+ SpellCheckerInfo getCurrentSpellChecker(String locale);
+ oneway void getSpellCheckerService(in SpellCheckerInfo info, in String locale,
+ in ITextServicesSessionListener tsListener,
+ in ISpellCheckerSessionListener scListener);
+ oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener);
+}
diff --git a/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl b/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl
new file mode 100644
index 000000000000..ecb6cd0f85d1
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSession;
+
+import android.view.textservice.SpellCheckerInfo;
+
+/**
+ * Interface to the text service session.
+ * @hide
+ */
+interface ITextServicesSessionListener {
+ oneway void onServiceConnected(in ISpellCheckerSession spellCheckerSession);
+}
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 164d5811c31e..159b3da440bd 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -50,6 +50,8 @@ public class MenuBuilder implements Menu {
private static final String LOGTAG = "MenuBuilder";
private static final String PRESENTER_KEY = "android:menu:presenters";
+ private static final String ACTION_VIEW_STATES_KEY = "android:menu:actionviewstates";
+ private static final String EXPANDED_ACTION_VIEW_ID = "android:menu:expandedactionview";
private static final int[] sCategoryToOrder = new int[] {
1, /* No category */
@@ -308,6 +310,67 @@ public class MenuBuilder implements Menu {
dispatchRestoreInstanceState(state);
}
+ public void saveActionViewStates(Bundle outStates) {
+ SparseArray<Parcelable> viewStates = null;
+
+ final int itemCount = size();
+ for (int i = 0; i < itemCount; i++) {
+ final MenuItem item = getItem(i);
+ final View v = item.getActionView();
+ if (v != null && v.getId() != View.NO_ID) {
+ if (viewStates == null) {
+ viewStates = new SparseArray<Parcelable>();
+ }
+ v.saveHierarchyState(viewStates);
+ if (item.isActionViewExpanded()) {
+ outStates.putInt(EXPANDED_ACTION_VIEW_ID, item.getItemId());
+ }
+ }
+ if (item.hasSubMenu()) {
+ final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+ subMenu.saveActionViewStates(outStates);
+ }
+ }
+
+ if (viewStates != null) {
+ outStates.putSparseParcelableArray(getActionViewStatesKey(), viewStates);
+ }
+ }
+
+ public void restoreActionViewStates(Bundle states) {
+ if (states == null) {
+ return;
+ }
+
+ SparseArray<Parcelable> viewStates = states.getSparseParcelableArray(
+ getActionViewStatesKey());
+
+ final int itemCount = size();
+ for (int i = 0; i < itemCount; i++) {
+ final MenuItem item = getItem(i);
+ final View v = item.getActionView();
+ if (v != null && v.getId() != View.NO_ID) {
+ v.restoreHierarchyState(viewStates);
+ }
+ if (item.hasSubMenu()) {
+ final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+ subMenu.restoreActionViewStates(states);
+ }
+ }
+
+ final int expandedId = states.getInt(EXPANDED_ACTION_VIEW_ID);
+ if (expandedId > 0) {
+ MenuItem itemToExpand = findItem(expandedId);
+ if (itemToExpand != null) {
+ itemToExpand.expandActionView();
+ }
+ }
+ }
+
+ protected String getActionViewStatesKey() {
+ return ACTION_VIEW_STATES_KEY;
+ }
+
public void setCallback(Callback cb) {
mCallback = cb;
}
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 541d10120dd6..b0a002d2ce8d 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -553,6 +553,9 @@ public final class MenuItemImpl implements MenuItem {
public MenuItem setActionView(View view) {
mActionView = view;
mActionProvider = null;
+ if (view != null && view.getId() == View.NO_ID && mId > 0) {
+ view.setId(mId);
+ }
mMenu.onItemActionRequestChanged(this);
return this;
}
diff --git a/core/java/com/android/internal/view/menu/SubMenuBuilder.java b/core/java/com/android/internal/view/menu/SubMenuBuilder.java
index fb1cd5e81ef7..92acf8cda8f5 100644
--- a/core/java/com/android/internal/view/menu/SubMenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/SubMenuBuilder.java
@@ -121,4 +121,13 @@ public class SubMenuBuilder extends MenuBuilder implements SubMenu {
public boolean collapseItemActionView(MenuItemImpl item) {
return mParentMenu.collapseItemActionView(item);
}
+
+ @Override
+ public String getActionViewStatesKey() {
+ final int itemId = mItem != null ? mItem.getItemId() : 0;
+ if (itemId == 0) {
+ return null;
+ }
+ return super.getActionViewStatesKey() + ":" + itemId;
+ }
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index e03858b4af13..8b74f3d00428 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -42,6 +42,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.CollapsibleActionView;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -1304,6 +1305,10 @@ public class ActionBarView extends AbsActionBarView {
if (mCustomNavView != null) mCustomNavView.setVisibility(GONE);
requestLayout();
item.setActionViewExpanded(true);
+
+ if (mExpandedActionView instanceof CollapsibleActionView) {
+ ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded();
+ }
return true;
}
@@ -1330,11 +1335,16 @@ public class ActionBarView extends AbsActionBarView {
if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
mCustomNavView.setVisibility(VISIBLE);
}
+ View collapsedView = mExpandedActionView;
mExpandedActionView = null;
mExpandedHomeLayout.setIcon(null);
mCurrentExpandedItem = null;
requestLayout();
item.setActionViewExpanded(false);
+
+ if (collapsedView instanceof CollapsibleActionView) {
+ ((CollapsibleActionView) collapsedView).onActionViewCollapsed();
+ }
return true;
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index b0c2f2c2da07..b06de9d1b91e 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -576,18 +576,18 @@ static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
// ----------------------------------------------------------------------------
static DisplayList* android_view_GLES20Canvas_getDisplayList(JNIEnv* env,
- jobject clazz, DisplayListRenderer* renderer) {
- return renderer->getDisplayList();
+ jobject clazz, DisplayListRenderer* renderer, DisplayList* displayList) {
+ return renderer->getDisplayList(displayList);
+}
+
+static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
+ jobject clazz) {
+ return new DisplayListRenderer;
}
-static OpenGLRenderer* android_view_GLES20Canvas_getDisplayListRenderer(JNIEnv* env,
+static void android_view_GLES20Canvas_resetDisplayListRenderer(JNIEnv* env,
jobject clazz, DisplayListRenderer* renderer) {
- if (renderer == NULL) {
- renderer = new DisplayListRenderer;
- } else {
- renderer->reset();
- }
- return renderer;
+ renderer->reset();
}
static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env,
@@ -812,9 +812,10 @@ static JNINativeMethod gMethods[] = {
{ "nGetClipBounds", "(ILandroid/graphics/Rect;)Z",
(void*) android_view_GLES20Canvas_getClipBounds },
- { "nGetDisplayList", "(I)I", (void*) android_view_GLES20Canvas_getDisplayList },
+ { "nGetDisplayList", "(II)I", (void*) android_view_GLES20Canvas_getDisplayList },
{ "nDestroyDisplayList", "(I)V", (void*) android_view_GLES20Canvas_destroyDisplayList },
- { "nGetDisplayListRenderer", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListRenderer },
+ { "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer },
+ { "nResetDisplayListRenderer", "(I)V", (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
{ "nDrawDisplayList", "(IIIILandroid/graphics/Rect;)Z",
(void*) android_view_GLES20Canvas_drawDisplayList },
{ "nOutputDisplayList", "(II)V", (void*) android_view_GLES20Canvas_outputDisplayList },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c67b6252253a..91003d181b9c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1120,6 +1120,13 @@
android:description="@string/permdesc_bindInputMethod"
android:protectionLevel="signature" />
+ <!-- Must be required by a TextService (e.g. SpellCheckerService)
+ to ensure that only the system can bind to it. -->
+ <permission android:name="android.permission.BIND_TEXT_SERVICE"
+ android:label="@string/permlab_bindTextService"
+ android:description="@string/permdesc_bindTextService"
+ android:protectionLevel="signature" />
+
<!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
to ensure that only the system can bind to it. -->
<permission android:name="android.permission.BIND_WALLPAPER"
diff --git a/core/res/res/anim/screen_rotate_minus_90_enter.xml b/core/res/res/anim/screen_rotate_minus_90_enter.xml
index 30518e02784b..61aa72a3b307 100644
--- a/core/res/res/anim/screen_rotate_minus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_enter.xml
@@ -19,11 +19,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
- <scale android:fromXScale="100%p" android:toXScale="100%"
- android:fromYScale="100%p" android:toYScale="100%"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_mediumAnimTime" />
<rotate android:fromDegrees="-90" android:toDegrees="0"
android:pivotX="50%" android:pivotY="50%"
android:interpolator="@interpolator/decelerate_quint"
diff --git a/core/res/res/anim/screen_rotate_plus_90_enter.xml b/core/res/res/anim/screen_rotate_plus_90_enter.xml
index 20943c853578..53b0ccd43f05 100644
--- a/core/res/res/anim/screen_rotate_plus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_enter.xml
@@ -19,11 +19,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
- <scale android:fromXScale="100%p" android:toXScale="100%"
- android:fromYScale="100%p" android:toYScale="100%"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_mediumAnimTime" />
<rotate android:fromDegrees="90" android:toDegrees="0"
android:pivotX="50%" android:pivotY="50%"
android:interpolator="@interpolator/decelerate_quint"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5b25e2dff638..feac38d6d695 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -705,6 +705,12 @@
interface of an input method. Should never be needed for normal applications.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindTextService">bind to a text service</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindTextService">Allows the holder to bind to the top-level
+ interface of a text service(e.g. SpellCheckerService). Should never be needed for normal applications.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_bindWallpaper">bind to a wallpaper</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindWallpaper">Allows the holder to bind to the top-level
diff --git a/docs/html/guide/developing/tools/adb.jd b/docs/html/guide/developing/tools/adb.jd
index 78d12effd8b7..d32cf6684eda 100644
--- a/docs/html/guide/developing/tools/adb.jd
+++ b/docs/html/guide/developing/tools/adb.jd
@@ -280,7 +280,7 @@ instance, see <a href="{@docRoot}guide/developing/building/index.html">Building
<td>Run PPP over USB.
<ul>
<li><code>&lt;tty&gt;</code> &mdash; the tty for PPP stream. For example <code>dev:/dev/omap_csmi_ttyl</code>. </li>
-<li><code>[parm]... </code> &mdash zero or more PPP/PPPD options, such as <code>defaultroute</code>, <code>local</code>, <code>notty</code>, etc.</li></ul>
+<li><code>[parm]... </code> &mdash; zero or more PPP/PPPD options, such as <code>defaultroute</code>, <code>local</code>, <code>notty</code>, etc.</li></ul>
<p>Note that you should not automatically start a PPP connection. </p></td>
<td></td>
diff --git a/docs/html/guide/topics/intents/intents-filters.jd b/docs/html/guide/topics/intents/intents-filters.jd
index 59052143523e..3f9455391a86 100644
--- a/docs/html/guide/topics/intents/intents-filters.jd
+++ b/docs/html/guide/topics/intents/intents-filters.jd
@@ -927,7 +927,7 @@ as described by its two intent filters:
<p>
The first, primary, purpose of this activity is to enable the user to
-interact with a single note &mdash to either {@code VIEW} the note or
+interact with a single note &mdash; to either {@code VIEW} the note or
{@code EDIT} it. (The {@code EDIT_NOTE} category is a synonym for
{@code EDIT}.) The intent would contain the URI for data matching the
MIME type <code>vnd.android.cursor.item/vnd.google.note</code> &mdash;
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index 34862121ae82..743832c6e763 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -710,7 +710,7 @@ the soft keyboard.</li>
The setting must be one of the values listed in the following table, or a
combination of one "{@code state...}" value plus one "{@code adjust...}"
value. Setting multiple values in either group &mdash; multiple
-"{@code state...}" values, for example &mdash has undefined results.
+"{@code state...}" values, for example &mdash; has undefined results.
Individual values are separated by a vertical bar ({@code |}). For example:
</p>
@@ -801,4 +801,4 @@ Level 3.</dd>
<dt>see also:</dt>
<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code></dd>
-</dl> \ No newline at end of file
+</dl>
diff --git a/docs/html/guide/topics/providers/content-providers.jd b/docs/html/guide/topics/providers/content-providers.jd
index 2a84c263f652..513886afbe23 100644
--- a/docs/html/guide/topics/providers/content-providers.jd
+++ b/docs/html/guide/topics/providers/content-providers.jd
@@ -277,7 +277,7 @@ are returned. All the content providers that come with the platform define
constants for their columns. For example, the
{@link android.provider.Contacts.Phones android.provider.Contacts.Phones} class
defines constants for the names of the columns in the phone table illustrated
-earlier &mdash {@code _ID}, {@code NUMBER}, {@code NUMBER_KEY}, {@code NAME},
+earlier &mdash; {@code _ID}, {@code NUMBER}, {@code NUMBER_KEY}, {@code NAME},
and so on.</li>
<li><p>A filter detailing which rows to return, formatted as an SQL {@code WHERE}
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 4a85faf7dd2e..3476bd5aa646 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -504,6 +504,7 @@ nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, RsContext con, jint alloc,
void* ptr = bitmap.getPixels();
rsAllocationCopyToBitmap(con, (RsAllocation)alloc, ptr, bitmap.getSize());
bitmap.unlockPixels();
+ bitmap.notifyPixelsChanged();
}
static void ReleaseBitmapCallback(void *bmp)
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 48d1464336a1..713af92860ef 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -20,6 +20,7 @@
#include <sys/types.h>
+#include <media/stagefright/MediaErrors.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/List.h>
@@ -61,6 +62,10 @@ public:
return 0;
}
+ virtual status_t reconnectAtOffset(off64_t offset) {
+ return ERROR_UNSUPPORTED;
+ }
+
////////////////////////////////////////////////////////////////////////////
bool sniff(String8 *mimeType, float *confidence, sp<AMessage> *meta);
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 1dc6cd2cf751..986fc7e37164 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -55,6 +55,9 @@ void SurfaceTextureClient::init() {
mQueryWidth = 0;
mQueryHeight = 0;
mQueryFormat = 0;
+ mDefaultWidth = 0;
+ mDefaultHeight = 0;
+ mTransformHint = 0;
mConnectedToCpu = false;
}
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 8b1caeeedf59..886c05c64c07 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -883,7 +883,6 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
///////////////////////////////////////////////////////////////////////////////
DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE) {
- mDisplayList = NULL;
}
DisplayListRenderer::~DisplayListRenderer() {
@@ -923,13 +922,13 @@ void DisplayListRenderer::reset() {
// Operations
///////////////////////////////////////////////////////////////////////////////
-DisplayList* DisplayListRenderer::getDisplayList() {
- if (mDisplayList == NULL) {
- mDisplayList = new DisplayList(*this);
+DisplayList* DisplayListRenderer::getDisplayList(DisplayList* displayList) {
+ if (!displayList) {
+ displayList = new DisplayList(*this);
} else {
- mDisplayList->initFromDisplayListRenderer(*this, true);
+ displayList->initFromDisplayListRenderer(*this, true);
}
- return mDisplayList;
+ return displayList;
}
void DisplayListRenderer::setViewport(int width, int height) {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index b83259f82450..81576313c15f 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -217,7 +217,7 @@ public:
DisplayListRenderer();
~DisplayListRenderer();
- DisplayList* getDisplayList();
+ DisplayList* getDisplayList(DisplayList* displayList);
void setViewport(int width, int height);
void prepareDirty(float left, float top, float right, float bottom, bool opaque);
@@ -474,8 +474,6 @@ private:
SkWriter32 mWriter;
- DisplayList *mDisplayList;
-
int mRestoreSaveCount;
friend class DisplayList;
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 412552ec8eca..0e8ae619fc5c 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -310,35 +310,21 @@ int FramebufferNativeWindow::perform(ANativeWindow* window,
int operation, ...)
{
switch (operation) {
- case NATIVE_WINDOW_SET_USAGE:
- // TODO: we should implement this
- return NO_ERROR;
case NATIVE_WINDOW_CONNECT:
- // TODO: we should implement this
- return NO_ERROR;
case NATIVE_WINDOW_DISCONNECT:
- // TODO: we should implement this
+ case NATIVE_WINDOW_SET_USAGE:
+ case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+ case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+ case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+ // TODO: we should implement these
return NO_ERROR;
+
case NATIVE_WINDOW_LOCK:
- return INVALID_OPERATION;
case NATIVE_WINDOW_UNLOCK_AND_POST:
- return INVALID_OPERATION;
case NATIVE_WINDOW_SET_CROP:
- return INVALID_OPERATION;
case NATIVE_WINDOW_SET_BUFFER_COUNT:
- // TODO: we should implement this
- return INVALID_OPERATION;
- case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
- return INVALID_OPERATION;
- case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
- return INVALID_OPERATION;
case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
- return INVALID_OPERATION;
- case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
- return INVALID_OPERATION;
- case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
- // TODO: we should implement this
- return NO_ERROR;
case NATIVE_WINDOW_SET_SCALING_MODE:
return INVALID_OPERATION;
}
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index ed6e3c7aa7a5..a11fb804f134 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -228,6 +228,7 @@ status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
NATIVE_WINDOW_API_MEDIA);
if (err != OK) {
+ LOGE("setVideoSurface failed: %d", err);
// Note that we must do the reset before disconnecting from the ANW.
// Otherwise queue/dequeue calls could be made on the disconnected
// ANW, which may result in errors.
@@ -277,6 +278,7 @@ status_t MediaPlayer::setVideoSurfaceTexture(
NATIVE_WINDOW_API_MEDIA);
if (err != OK) {
+ LOGE("setVideoSurfaceTexture failed: %d", err);
// Note that we must do the reset before disconnecting from the ANW.
// Otherwise queue/dequeue calls could be made on the disconnected
// ANW, which may result in errors.
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 77a66024a60d..4edb613c33b6 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -185,7 +185,8 @@ NuCachedSource2::NuCachedSource2(const sp<DataSource> &source)
mFinalStatus(OK),
mLastAccessPos(0),
mFetching(true),
- mLastFetchTimeUs(-1) {
+ mLastFetchTimeUs(-1),
+ mNumRetriesLeft(kMaxNumRetries) {
mLooper->setName("NuCachedSource2");
mLooper->registerHandler(mReflector);
mLooper->start();
@@ -254,7 +255,27 @@ void NuCachedSource2::onMessageReceived(const sp<AMessage> &msg) {
void NuCachedSource2::fetchInternal() {
LOGV("fetchInternal");
- CHECK_EQ(mFinalStatus, (status_t)OK);
+ {
+ Mutex::Autolock autoLock(mLock);
+ CHECK(mFinalStatus == OK || mNumRetriesLeft > 0);
+
+ if (mFinalStatus != OK) {
+ --mNumRetriesLeft;
+
+ status_t err =
+ mSource->reconnectAtOffset(mCacheOffset + mCache->totalSize());
+
+ if (err == ERROR_UNSUPPORTED) {
+ mNumRetriesLeft = 0;
+ return;
+ } else if (err != OK) {
+ LOGI("The attempt to reconnect failed, %d retries remaining",
+ mNumRetriesLeft);
+
+ return;
+ }
+ }
+ }
PageCache::Page *page = mCache->acquirePage();
@@ -264,14 +285,23 @@ void NuCachedSource2::fetchInternal() {
Mutex::Autolock autoLock(mLock);
if (n < 0) {
- LOGE("source returned error %ld", n);
+ LOGE("source returned error %ld, %d retries left", n, mNumRetriesLeft);
mFinalStatus = n;
mCache->releasePage(page);
} else if (n == 0) {
LOGI("ERROR_END_OF_STREAM");
+
+ mNumRetriesLeft = 0;
mFinalStatus = ERROR_END_OF_STREAM;
+
mCache->releasePage(page);
} else {
+ if (mFinalStatus != OK) {
+ LOGI("retrying a previously failed read succeeded.");
+ }
+ mNumRetriesLeft = kMaxNumRetries;
+ mFinalStatus = OK;
+
page->mSize = n;
mCache->appendPage(page);
}
@@ -280,7 +310,7 @@ void NuCachedSource2::fetchInternal() {
void NuCachedSource2::onFetch() {
LOGV("onFetch");
- if (mFinalStatus != OK) {
+ if (mFinalStatus != OK && mNumRetriesLeft == 0) {
LOGV("EOS reached, done prefetching for now");
mFetching = false;
}
@@ -308,8 +338,19 @@ void NuCachedSource2::onFetch() {
restartPrefetcherIfNecessary_l();
}
- (new AMessage(kWhatFetchMore, mReflector->id()))->post(
- mFetching ? 0 : 100000ll);
+ int64_t delayUs;
+ if (mFetching) {
+ if (mFinalStatus != OK && mNumRetriesLeft > 0) {
+ // We failed this time and will try again in 3 seconds.
+ delayUs = 3000000ll;
+ } else {
+ delayUs = 0;
+ }
+ } else {
+ delayUs = 100000ll;
+ }
+
+ (new AMessage(kWhatFetchMore, mReflector->id()))->post(delayUs);
}
void NuCachedSource2::onRead(const sp<AMessage> &msg) {
@@ -345,7 +386,7 @@ void NuCachedSource2::restartPrefetcherIfNecessary_l(
bool ignoreLowWaterThreshold, bool force) {
static const size_t kGrayArea = 1024 * 1024;
- if (mFetching || mFinalStatus != OK) {
+ if (mFetching || (mFinalStatus != OK && mNumRetriesLeft == 0)) {
return;
}
@@ -427,6 +468,12 @@ size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) {
size_t NuCachedSource2::approxDataRemaining_l(status_t *finalStatus) {
*finalStatus = mFinalStatus;
+
+ if (mFinalStatus != OK && mNumRetriesLeft > 0) {
+ // Pretend that everything is fine until we're out of retries.
+ *finalStatus = OK;
+ }
+
off64_t lastBytePosCached = mCacheOffset + mCache->totalSize();
if (mLastAccessPos < lastBytePosCached) {
return lastBytePosCached - mLastAccessPos;
diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
index 588a74d99242..07a9eb892c5d 100644
--- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
+++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
@@ -25,6 +25,8 @@
#include "support.h"
+#include <cutils/properties.h> // for property_get
+
namespace android {
ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags)
@@ -111,7 +113,7 @@ void ChromiumHTTPDataSource::onConnectionFailed(status_t err) {
mState = DISCONNECTED;
mCondition.broadcast();
- mURI.clear();
+ // mURI.clear();
mIOResult = err;
@@ -150,8 +152,18 @@ ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size)
Mutex::Autolock autoLock(mLock);
if (mState != CONNECTED) {
- return ERROR_NOT_CONNECTED;
+ return INVALID_OPERATION;
+ }
+
+#if 0
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.stagefright.disable-net", value, 0)
+ && (!strcasecmp(value, "true") || !strcmp(value, "1"))) {
+ LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Simulating that the network is down.");
+ disconnect_l();
+ return ERROR_IO;
}
+#endif
if (offset != mCurrentOffset) {
AString tmp = mURI;
@@ -236,7 +248,7 @@ void ChromiumHTTPDataSource::onDisconnectComplete() {
CHECK_EQ((int)mState, (int)DISCONNECTING);
mState = DISCONNECTED;
- mURI.clear();
+ // mURI.clear();
mCondition.broadcast();
@@ -299,5 +311,21 @@ void ChromiumHTTPDataSource::clearDRMState_l() {
}
}
+status_t ChromiumHTTPDataSource::reconnectAtOffset(off64_t offset) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mURI.empty()) {
+ return INVALID_OPERATION;
+ }
+
+ LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnecting...");
+ status_t err = connect_l(mURI.c_str(), &mHeaders, offset);
+ if (err != OK) {
+ LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnect failed w/ err 0x%08x", err);
+ }
+
+ return err;
+}
+
} // namespace android
diff --git a/media/libstagefright/include/ChromiumHTTPDataSource.h b/media/libstagefright/include/ChromiumHTTPDataSource.h
index d833e2efc1ba..18f89130c747 100644
--- a/media/libstagefright/include/ChromiumHTTPDataSource.h
+++ b/media/libstagefright/include/ChromiumHTTPDataSource.h
@@ -51,6 +51,8 @@ struct ChromiumHTTPDataSource : public HTTPBase {
virtual String8 getMIMEType() const;
+ virtual status_t reconnectAtOffset(off64_t offset);
+
protected:
virtual ~ChromiumHTTPDataSource();
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 2d6cb848292a..22b2855204e9 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -77,6 +77,10 @@ private:
kWhatRead = 'read',
};
+ enum {
+ kMaxNumRetries = 10,
+ };
+
sp<DataSource> mSource;
sp<AHandlerReflector<NuCachedSource2> > mReflector;
sp<ALooper> mLooper;
@@ -93,6 +97,8 @@ private:
bool mFetching;
int64_t mLastFetchTimeUs;
+ int32_t mNumRetriesLeft;
+
void onMessageReceived(const sp<AMessage> &msg);
void onFetch();
void onRead(const sp<AMessage> &msg);
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 5298f2e66927..d7d7817fc15b 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -34,7 +34,7 @@
<string name="config_systemBarComponent" translatable="false">com.android.systemui.statusbar.tablet.TabletStatusBar</string>
<!-- Whether or not we show the number in the bar. -->
- <bool name="config_statusBarShowNumber">true</bool>
+ <bool name="config_statusBarShowNumber">false</bool>
<!-- How many icons may be shown at once in the system bar. Includes any
slots that may be reused for things like IME control. -->
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index cca7947e827d..ea544456430d 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -329,6 +329,7 @@ public class RecentsPanelView extends RelativeLayout
mRecentsGlowView = findViewById(R.id.recents_glow);
+ mRecentsScrim = (View) findViewById(R.id.recents_bg_protect);
mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView, this);
mRecentsDismissButton = findViewById(R.id.recents_dismiss_button);
mRecentsDismissButton.setOnClickListener(new OnClickListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index b4d2a14ecb07..d5885bb81c25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -148,6 +148,11 @@ public class NotificationRowLayout extends ViewGroup {
"now sliding child %d: %s (touchY=%.1f, rowHeight=%d, count=%d)",
childIdx, mSlidingChild, mInitialTouchY, mRowHeight, count));
}
+
+
+ // We need to prevent the surrounding ScrollView from intercepting us now;
+ // the scroll position will be locked while we swipe
+ requestDisallowInterceptTouchEvent(true);
}
}
break;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index b963b131f59f..e0debf7ca994 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -388,6 +388,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
st.isHandled = false;
mPreparedPanel = st;
+ if (st.frozenActionViewState != null) {
+ st.menu.restoreActionViewStates(st.frozenActionViewState);
+ st.frozenActionViewState = null;
+ }
+
return true;
}
@@ -652,7 +657,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public void invalidatePanelMenu(int featureId) {
PanelFeatureState st = getPanelState(featureId, true);
+ Bundle savedActionViewStates = null;
if (st.menu != null) {
+ savedActionViewStates = new Bundle();
+ st.menu.saveActionViewStates(savedActionViewStates);
+ if (savedActionViewStates.size() > 0) {
+ st.frozenActionViewState = savedActionViewStates;
+ }
st.menu.clear();
}
st.refreshMenuContent = true;
@@ -3024,6 +3035,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
*/
Bundle frozenMenuState;
+ /**
+ * Contains the state of associated action views when told to freeze.
+ * These are saved across invalidations.
+ */
+ Bundle frozenActionViewState;
+
PanelFeatureState(int featureId) {
this.featureId = featureId;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ad6cebb60b78..ae13ab5a17a9 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -166,22 +166,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static final int SYSTEM_DIALOG_LAYER = 6;
// toasts and the plugged-in battery thing
static final int TOAST_LAYER = 7;
- static final int STATUS_BAR_LAYER = 8;
- static final int STATUS_BAR_PANEL_LAYER = 9;
// SIM errors and unlock. Not sure if this really should be in a high layer.
- static final int PRIORITY_PHONE_LAYER = 10;
+ static final int PRIORITY_PHONE_LAYER = 8;
// like the ANR / app crashed dialogs
- static final int SYSTEM_ALERT_LAYER = 11;
+ static final int SYSTEM_ALERT_LAYER = 9;
// system-level error dialogs
- static final int SYSTEM_ERROR_LAYER = 12;
+ static final int SYSTEM_ERROR_LAYER = 10;
// on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_LAYER = 13;
+ static final int INPUT_METHOD_LAYER = 11;
// on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_DIALOG_LAYER = 14;
+ static final int INPUT_METHOD_DIALOG_LAYER = 12;
// the keyguard; nothing on top of these can take focus, since they are
// responsible for power management when displayed.
- static final int KEYGUARD_LAYER = 15;
- static final int KEYGUARD_DIALOG_LAYER = 16;
+ static final int KEYGUARD_LAYER = 13;
+ static final int KEYGUARD_DIALOG_LAYER = 14;
+ static final int STATUS_BAR_LAYER = 15;
+ static final int STATUS_BAR_PANEL_LAYER = 16;
// the navigation bar, if available, shows atop most things
static final int NAVIGATION_BAR_LAYER = 17;
// the drag layer: input for drag-and-drop is associated with this window,
@@ -1703,7 +1703,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
}
- if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + navr);
+ if (DEBUG_LAYOUT) {
+ Log.i(TAG, "mNavigationBar frame: " + navr);
+ Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
+ mDockLeft, mDockTop, mDockRight, mDockBottom));
+ }
// apply navigation bar insets
pf.left = df.left = vf.left = mDockLeft;
@@ -1713,6 +1717,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mStatusBar.computeFrameLw(pf, df, vf, vf);
+ // now, let's consider the navigation bar; if it exists, it must be removed from the
+ // available screen real estate (like an un-hideable status bar)
+ if (navr != null) {
+ if (navr.top == 0) {
+ // Navigation bar is vertical
+ if (mRestrictedScreenLeft == navr.left) {
+ mRestrictedScreenLeft = navr.right;
+ mRestrictedScreenWidth -= (navr.right - navr.left);
+ } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) {
+ mRestrictedScreenWidth -= (navr.right - navr.left);
+ }
+ } else {
+ // Navigation bar horizontal, at bottom
+ if ((mRestrictedScreenHeight+mRestrictedScreenTop) == navr.bottom) {
+ mRestrictedScreenHeight -= (navr.bottom-navr.top);
+ }
+ }
+ }
+
if (mStatusBar.isVisibleLw()) {
// If the status bar is hidden, we don't want to cause
// windows behind it to scroll.
@@ -1745,23 +1768,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mRestrictedScreenHeight -= (r.bottom-r.top);
}
- if (navr != null) {
- if (navr.top == 0) {
- // Navigation bar is vertical
- if (mRestrictedScreenLeft == navr.left) {
- mRestrictedScreenLeft = navr.right;
- mRestrictedScreenWidth -= (navr.right - navr.left);
- } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) {
- mRestrictedScreenWidth -= (navr.right - navr.left);
- }
- } else {
- // Navigation bar horizontal, at bottom
- if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
- mRestrictedScreenHeight -= (navr.bottom-navr.top);
- }
- }
- }
-
mContentTop = mCurTop = mDockTop = mRestrictedScreenTop;
mContentBottom = mCurBottom = mDockBottom
= mRestrictedScreenTop + mRestrictedScreenHeight;
@@ -1873,19 +1879,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// permission, so they have the same privileges as the status
// bar itself.
//
- // However, they should still dodge the navigation bar if it exists. A
- // straightforward way to do this is to only allow the status bar panels to
- // extend to the extrema of the allowable region for the IME dock.
+ // However, they should still dodge the navigation bar if it exists.
pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
pf.top = df.top = mUnrestrictedScreenTop;
pf.right = df.right = hasNavBar
- ? mDockRight
+ ? mRestrictedScreenLeft+mRestrictedScreenWidth
: mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
pf.bottom = df.bottom = hasNavBar
- ? mDockBottom
+ ? mRestrictedScreenTop+mRestrictedScreenHeight
: mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ if (DEBUG_LAYOUT) {
+ Log.v(TAG, String.format(
+ "Laying out status bar window: (%d,%d - %d,%d)",
+ pf.left, pf.top, pf.right, pf.bottom));
+ }
} else {
pf.left = df.left = mRestrictedScreenLeft;
pf.top = df.top = mRestrictedScreenTop;
@@ -1922,12 +1931,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
pf.top = df.top = cf.top = mUnrestrictedScreenTop;
pf.right = df.right = cf.right = hasNavBar
- ? mDockRight
+ ? mRestrictedScreenLeft+mRestrictedScreenWidth
: mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
pf.bottom = df.bottom = cf.bottom = hasNavBar
- ? mDockBottom
+ ? mRestrictedScreenTop+mRestrictedScreenHeight
: mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ } else if (attrs.type == TYPE_NAVIGATION_BAR) {
+ // The navigation bar has Real Ultimate Power.
+ pf.left = df.left = mUnrestrictedScreenLeft;
+ pf.top = df.top = mUnrestrictedScreenTop;
+ pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ if (DEBUG_LAYOUT) {
+ Log.v(TAG, String.format(
+ "Laying out navigation bar window: (%d,%d - %d,%d)",
+ pf.left, pf.top, pf.right, pf.bottom));
+ }
} else {
pf.left = df.left = cf.left = mRestrictedScreenLeft;
pf.top = df.top = cf.top = mRestrictedScreenTop;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 482336ba9eb8..0323fe0001a3 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2954,7 +2954,7 @@ AudioFlinger::PlaybackThread::Track::Track(
mStreamType = streamType;
// NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of
// 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack
- mCblk->frameSize = audio_is_linear_pcm(format) ? mChannelCount * audio_bytes_per_sample(format) : sizeof(uint8_t);
+ mCblk->frameSize = audio_is_linear_pcm(format) ? mChannelCount * sizeof(int16_t) : sizeof(uint8_t);
}
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 73996795205e..d39f565f7f84 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -166,7 +166,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private final KeyguardManager mKeyguardManager;
private final Notification mImeSwitcherNotification;
private final PendingIntent mImeSwitchPendingIntent;
- private final boolean mShowOngoingImeSwitcherForPhones;
+ private boolean mShowOngoingImeSwitcherForPhones;
private boolean mNotificationShown;
class SessionState {
@@ -538,8 +538,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mImeSwitcherNotification.vibrate = null;
Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
- mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
- com.android.internal.R.bool.show_ongoing_ime_switcher);
+
+ mShowOngoingImeSwitcherForPhones = false;
synchronized (mMethodMap) {
mFileManager = new InputMethodFileManager(mMethodMap);
@@ -612,6 +612,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
synchronized (mMethodMap) {
if (!mSystemReady) {
mSystemReady = true;
+ mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
+ com.android.internal.R.bool.show_ongoing_ime_switcher);
try {
startInputInnerLocked();
} catch (RuntimeException e) {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 41e8a3148223..2366fcb41c8d 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -93,6 +93,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
private static final String KEY_TX = "tx_bytes";
class NetdResponseCode {
+ /* Keep in sync with system/netd/ResponseCode.h */
public static final int InterfaceListResult = 110;
public static final int TetherInterfaceListResult = 111;
public static final int TetherDnsFwdTgtListResult = 112;
@@ -108,6 +109,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
public static final int InterfaceTxThrottleResult = 219;
public static final int InterfaceChange = 600;
+ public static final int BandwidthControl = 601;
}
/**
@@ -265,6 +267,20 @@ class NetworkManagementService extends INetworkManagementService.Stub {
}
/**
+ * Notify our observers of a limit reached.
+ */
+ private void notifyLimitReached(String limitName, String iface) {
+ for (INetworkManagementEventObserver obs : mObservers) {
+ try {
+ obs.limitReached(limitName, iface);
+ Slog.d(TAG, "Observer notified limit reached for " + limitName + " " + iface);
+ } catch (Exception ex) {
+ Slog.w(TAG, "Observer notifier failed", ex);
+ }
+ }
+ }
+
+ /**
* Let us know the daemon is connected
*/
protected void onConnected() {
@@ -286,33 +302,52 @@ class NetworkManagementService extends INetworkManagementService.Stub {
}.start();
}
public boolean onEvent(int code, String raw, String[] cooked) {
- if (code == NetdResponseCode.InterfaceChange) {
- /*
- * a network interface change occured
- * Format: "NNN Iface added <name>"
- * "NNN Iface removed <name>"
- * "NNN Iface changed <name> <up/down>"
- * "NNN Iface linkstatus <name> <up/down>"
- */
- if (cooked.length < 4 || !cooked[1].equals("Iface")) {
+ switch (code) {
+ case NetdResponseCode.InterfaceChange:
+ /*
+ * a network interface change occured
+ * Format: "NNN Iface added <name>"
+ * "NNN Iface removed <name>"
+ * "NNN Iface changed <name> <up/down>"
+ * "NNN Iface linkstatus <name> <up/down>"
+ */
+ if (cooked.length < 4 || !cooked[1].equals("Iface")) {
+ throw new IllegalStateException(
+ String.format("Invalid event from daemon (%s)", raw));
+ }
+ if (cooked[2].equals("added")) {
+ notifyInterfaceAdded(cooked[3]);
+ return true;
+ } else if (cooked[2].equals("removed")) {
+ notifyInterfaceRemoved(cooked[3]);
+ return true;
+ } else if (cooked[2].equals("changed") && cooked.length == 5) {
+ notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
+ return true;
+ } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
+ notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
+ return true;
+ }
throw new IllegalStateException(
String.format("Invalid event from daemon (%s)", raw));
- }
- if (cooked[2].equals("added")) {
- notifyInterfaceAdded(cooked[3]);
- return true;
- } else if (cooked[2].equals("removed")) {
- notifyInterfaceRemoved(cooked[3]);
- return true;
- } else if (cooked[2].equals("changed") && cooked.length == 5) {
- notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
- return true;
- } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
- notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
- return true;
- }
- throw new IllegalStateException(
- String.format("Invalid event from daemon (%s)", raw));
+ // break;
+ case NetdResponseCode.BandwidthControl:
+ /*
+ * Bandwidth control needs some attention
+ * Format: "NNN limit alert <alertName> <ifaceName>"
+ */
+ if (cooked.length < 5 || !cooked[1].equals("limit")) {
+ throw new IllegalStateException(
+ String.format("Invalid event from daemon (%s)", raw));
+ }
+ if (cooked[2].equals("alert")) {
+ notifyLimitReached(cooked[3], cooked[4]);
+ return true;
+ }
+ throw new IllegalStateException(
+ String.format("Invalid event from daemon (%s)", raw));
+ // break;
+ default: break;
}
return false;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8c7e279b7132..766659153821 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -230,6 +230,7 @@ class ServerThread extends Thread {
WallpaperManagerService wallpaper = null;
LocationManagerService location = null;
CountryDetectorService countryDetector = null;
+ TextServicesManagerService tsms = null;
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
try {
@@ -273,6 +274,14 @@ class ServerThread extends Thread {
}
try {
+ Slog.i(TAG, "Text Service Manager Service");
+ tsms = new TextServicesManagerService(context);
+ ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting Text Service Manager Service", e);
+ }
+
+ try {
Slog.i(TAG, "NetworkStats Service");
networkStats = new NetworkStatsService(context, networkManagement, alarm);
ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
@@ -538,6 +547,7 @@ class ServerThread extends Thread {
final LocationManagerService locationF = location;
final CountryDetectorService countryDetectorF = countryDetector;
final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
+ final TextServicesManagerService textServiceManagerServiceF = tsms;
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
@@ -571,6 +581,7 @@ class ServerThread extends Thread {
if (countryDetectorF != null) countryDetectorF.systemReady();
if (throttleF != null) throttleF.systemReady();
if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady();
+ if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady();
}
});
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
new file mode 100644
index 000000000000..4a0c837df0c6
--- /dev/null
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.textservice.ISpellCheckerService;
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+import com.android.internal.textservice.ITextServicesManager;
+import com.android.internal.textservice.ITextServicesSessionListener;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.service.textservice.SpellCheckerService;
+import android.util.Log;
+import android.util.Slog;
+import android.view.textservice.SpellCheckerInfo;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+public class TextServicesManagerService extends ITextServicesManager.Stub {
+ private static final String TAG = TextServicesManagerService.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ private final Context mContext;
+ private boolean mSystemReady;
+ private final TextServicesMonitor mMonitor;
+ private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap =
+ new HashMap<String, SpellCheckerInfo>();
+ private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>();
+ private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups =
+ new HashMap<String, SpellCheckerBindGroup>();
+
+ public void systemReady() {
+ if (!mSystemReady) {
+ mSystemReady = true;
+ }
+ }
+
+ public TextServicesManagerService(Context context) {
+ mSystemReady = false;
+ mContext = context;
+ mMonitor = new TextServicesMonitor();
+ mMonitor.register(context, true);
+ synchronized (mSpellCheckerMap) {
+ buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap);
+ }
+ }
+
+ private class TextServicesMonitor extends PackageMonitor {
+ @Override
+ public void onSomePackagesChanged() {
+ synchronized (mSpellCheckerMap) {
+ buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap);
+ // TODO: Update for each locale
+ SpellCheckerInfo sci = getCurrentSpellChecker(null);
+ if (sci == null) {
+ sci = findAvailSpellCheckerLocked(null, null);
+ if (sci == null) return;
+ // Set the current spell checker if there is one or more spell checkers
+ // available. In this case, "sci" is the first one in the available spell
+ // checkers.
+ setCurrentSpellChecker(sci);
+ }
+ final String packageName = sci.getPackageName();
+ final int change = isPackageDisappearing(packageName);
+ if (change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE) {
+ // Package disappearing
+ setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName));
+ } else if (isPackageModified(packageName)) {
+ // Package modified
+ setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName));
+ }
+ }
+ }
+ }
+
+ private static void buildSpellCheckerMapLocked(Context context,
+ ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map) {
+ list.clear();
+ map.clear();
+ final PackageManager pm = context.getPackageManager();
+ List<ResolveInfo> services = pm.queryIntentServices(
+ new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA);
+ final int N = services.size();
+ for (int i = 0; i < N; ++i) {
+ final ResolveInfo ri = services.get(i);
+ final ServiceInfo si = ri.serviceInfo;
+ final ComponentName compName = new ComponentName(si.packageName, si.name);
+ if (!android.Manifest.permission.BIND_TEXT_SERVICE.equals(si.permission)) {
+ Slog.w(TAG, "Skipping text service " + compName
+ + ": it does not require the permission "
+ + android.Manifest.permission.BIND_TEXT_SERVICE);
+ continue;
+ }
+ if (DBG) Slog.d(TAG, "Add: " + compName);
+ final SpellCheckerInfo sci = new SpellCheckerInfo(context, ri);
+ list.add(sci);
+ map.put(sci.getId(), sci);
+ }
+ }
+
+ // TODO: find an appropriate spell checker for specified locale
+ private SpellCheckerInfo findAvailSpellCheckerLocked(String locale, String prefPackage) {
+ final int spellCheckersCount = mSpellCheckerList.size();
+ if (spellCheckersCount == 0) {
+ Slog.w(TAG, "no available spell checker services found");
+ return null;
+ }
+ if (prefPackage != null) {
+ for (int i = 0; i < spellCheckersCount; ++i) {
+ final SpellCheckerInfo sci = mSpellCheckerList.get(i);
+ if (prefPackage.equals(sci.getPackageName())) {
+ return sci;
+ }
+ }
+ }
+ if (spellCheckersCount > 1) {
+ Slog.w(TAG, "more than one spell checker service found, picking first");
+ }
+ return mSpellCheckerList.get(0);
+ }
+
+ // TODO: Save SpellCheckerService by supported languages. Currently only one spell
+ // checker is saved.
+ @Override
+ public SpellCheckerInfo getCurrentSpellChecker(String locale) {
+ synchronized (mSpellCheckerMap) {
+ final String curSpellCheckerId =
+ Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.SPELL_CHECKER_SERVICE);
+ if (TextUtils.isEmpty(curSpellCheckerId)) {
+ return null;
+ }
+ return mSpellCheckerMap.get(curSpellCheckerId);
+ }
+ }
+
+ @Override
+ public void getSpellCheckerService(SpellCheckerInfo info, String locale,
+ ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener) {
+ if (!mSystemReady) {
+ return;
+ }
+ if (info == null || tsListener == null) {
+ Slog.e(TAG, "getSpellCheckerService: Invalid input.");
+ return;
+ }
+ final String sciId = info.getId();
+ synchronized(mSpellCheckerMap) {
+ if (!mSpellCheckerMap.containsKey(sciId)) {
+ return;
+ }
+ if (mSpellCheckerBindGroups.containsKey(sciId)) {
+ mSpellCheckerBindGroups.get(sciId).addListener(tsListener, locale, scListener);
+ return;
+ }
+ final InternalServiceConnection connection = new InternalServiceConnection(
+ sciId, locale, scListener);
+ final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE);
+ serviceIntent.setComponent(info.getComponent());
+ if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
+ Slog.e(TAG, "Failed to get a spell checker service.");
+ return;
+ }
+ final SpellCheckerBindGroup group = new SpellCheckerBindGroup(
+ connection, tsListener, locale, scListener);
+ mSpellCheckerBindGroups.put(sciId, group);
+ }
+ return;
+ }
+
+ @Override
+ public void finishSpellCheckerService(ISpellCheckerSessionListener listener) {
+ synchronized(mSpellCheckerMap) {
+ for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) {
+ if (group == null) continue;
+ group.removeListener(listener);
+ }
+ }
+ }
+
+ private void setCurrentSpellChecker(SpellCheckerInfo sci) {
+ if (sci == null || mSpellCheckerMap.containsKey(sci.getId())) return;
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.SPELL_CHECKER_SERVICE, sci == null ? "" : sci.getId());
+ }
+
+ // SpellCheckerBindGroup contains active text service session listeners.
+ // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from
+ // mSpellCheckerBindGroups
+ private class SpellCheckerBindGroup {
+ final InternalServiceConnection mInternalConnection;
+ final ArrayList<InternalDeathRecipient> mListeners =
+ new ArrayList<InternalDeathRecipient>();
+
+ public SpellCheckerBindGroup(InternalServiceConnection connection,
+ ITextServicesSessionListener listener, String locale,
+ ISpellCheckerSessionListener scListener) {
+ mInternalConnection = connection;
+ addListener(listener, locale, scListener);
+ }
+
+ public void onServiceConnected(ISpellCheckerService spellChecker) {
+ synchronized(mSpellCheckerMap) {
+ for (InternalDeathRecipient listener : mListeners) {
+ try {
+ final ISpellCheckerSession session = spellChecker.getISpellCheckerSession(
+ listener.mScLocale, listener.mScListener);
+ listener.mTsListener.onServiceConnected(session);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
+ public void addListener(ITextServicesSessionListener tsListener, String locale,
+ ISpellCheckerSessionListener scListener) {
+ synchronized(mSpellCheckerMap) {
+ try {
+ final int size = mListeners.size();
+ for (int i = 0; i < size; ++i) {
+ if (mListeners.get(i).hasSpellCheckerListener(scListener)) {
+ // do not add the lister if the group already contains this.
+ return;
+ }
+ }
+ final InternalDeathRecipient recipient = new InternalDeathRecipient(
+ this, tsListener, locale, scListener);
+ scListener.asBinder().linkToDeath(recipient, 0);
+ mListeners.add(new InternalDeathRecipient(
+ this, tsListener, locale, scListener));
+ } catch(RemoteException e) {
+ // do nothing
+ }
+ cleanLocked();
+ }
+ }
+
+ public void removeListener(ISpellCheckerSessionListener listener) {
+ synchronized(mSpellCheckerMap) {
+ final int size = mListeners.size();
+ final ArrayList<InternalDeathRecipient> removeList =
+ new ArrayList<InternalDeathRecipient>();
+ for (int i = 0; i < size; ++i) {
+ final InternalDeathRecipient tempRecipient = mListeners.get(i);
+ if(tempRecipient.hasSpellCheckerListener(listener)) {
+ removeList.add(tempRecipient);
+ }
+ }
+ final int removeSize = removeList.size();
+ for (int i = 0; i < removeSize; ++i) {
+ mListeners.remove(removeList.get(i));
+ }
+ cleanLocked();
+ }
+ }
+
+ private void cleanLocked() {
+ if (mListeners.isEmpty()) {
+ mSpellCheckerBindGroups.remove(this);
+ // Unbind service when there is no active clients.
+ mContext.unbindService(mInternalConnection);
+ }
+ }
+ }
+
+ private class InternalServiceConnection implements ServiceConnection {
+ private final ISpellCheckerSessionListener mListener;
+ private final String mSciId;
+ private final String mLocale;
+ public InternalServiceConnection(
+ String id, String locale, ISpellCheckerSessionListener listener) {
+ mSciId = id;
+ mLocale = locale;
+ mListener = listener;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized(mSpellCheckerMap) {
+ ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service);
+ final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId);
+ if (group != null) {
+ group.onServiceConnected(spellChecker);
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mSpellCheckerBindGroups.remove(mSciId);
+ }
+ }
+
+ private class InternalDeathRecipient implements IBinder.DeathRecipient {
+ public final ITextServicesSessionListener mTsListener;
+ public final ISpellCheckerSessionListener mScListener;
+ public final String mScLocale;
+ private final SpellCheckerBindGroup mGroup;
+ public InternalDeathRecipient(SpellCheckerBindGroup group,
+ ITextServicesSessionListener tsListener, String scLocale,
+ ISpellCheckerSessionListener scListener) {
+ mTsListener = tsListener;
+ mScListener = scListener;
+ mScLocale = scLocale;
+ mGroup = group;
+ }
+
+ public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) {
+ return mScListener.equals(listener);
+ }
+
+ @Override
+ public void binderDied() {
+ mGroup.removeListener(mScListener);
+ }
+ }
+}
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index b8890aa2aa8e..cd649ce4c554 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -194,6 +194,7 @@ public class ThrottleService extends IThrottleManager.Stub {
}
public void interfaceRemoved(String iface) {}
+ public void limitReached(String limitName, String iface) {}
}
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index d7d4b0346795..82bc505ea707 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -288,6 +288,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
+ public void limitReached(String limitName, String iface) {}
+
public int tether(String iface) {
Log.d(TAG, "Tethering " + iface);
TetherInterfaceSM sm = null;
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 05e95a7d3d89..cf75d6bbaed0 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -248,6 +248,8 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
}
}
+ public void limitReached(String limitName, String iface) {}
+
private void showNotification(VpnConfig config, String label, Bitmap icon) {
NotificationManager nm = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
index d8fd7fe84a73..36f5dcb97056 100644
--- a/services/java/com/android/server/wm/BlackFrame.java
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -32,10 +32,12 @@ public class BlackFrame {
final int top;
final Surface surface;
- BlackSurface(SurfaceSession session, int layer, int l, int t, int w, int h)
+ BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b)
throws Surface.OutOfResourcesException {
left = l;
top = t;
+ int w = r-l;
+ int h = b-t;
surface = new Surface(session, 0, "BlackSurface",
-1, w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
if (WindowManagerService.SHOW_TRANSACTIONS ||
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 11f61ccb1ada..40659d4d16be 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -60,6 +60,10 @@ status_t SurfaceTextureLayer::queueBuffer(int buf, int64_t timestamp,
sp<Layer> layer(mLayer.promote());
if (layer != NULL) {
+ uint32_t orientation = layer->getOrientation();
+ if (orientation & Transform::ROT_INVALID) {
+ orientation = 0;
+ }
*outTransform = layer->getOrientation();
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 40a70a806ce1..a0961caaa40d 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -806,10 +806,10 @@ public abstract class PhoneBase extends Handler implements Phone {
mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));
}
- public void notifyDataConnection() {
+ public void notifyDataConnection(String reason) {
String types[] = getActiveApnTypes();
for (String apnType : types) {
- mNotifier.notifyDataConnection(this, null, apnType, getDataConnectionState(apnType));
+ mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));
}
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 0d551aade502..5df2edd6a281 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -134,8 +134,6 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
}
}
- // Not sure if this is needed in CDMALTE phone.
- // mDataRoaming = regCodeIsRoaming(regState);
mLteSS.setRadioTechnology(type);
mLteSS.setState(regCodeToServiceState(regState));
} else {
@@ -345,13 +343,14 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
}
if (cm.getSimState().isSIMReady()) {
- // SIM is found on the device. If ERI roaming is OFF, use operator name
- // from CSIM record.
+ // SIM is found on the device. If ERI roaming is OFF and SID/NID matches
+ // one configfured in SIM, use operator name from CSIM record.
boolean showSpn =
((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition();
int iconIndex = ss.getCdmaEriIconIndex();
- if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF)) {
+ if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) &&
+ isInHomeSidNid(ss.getSystemId(), ss.getNetworkId())) {
ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName());
}
}
@@ -401,7 +400,7 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
}
if ((hasCdmaDataConnectionChanged || hasNetworkTypeChanged)) {
- phone.notifyDataConnection();
+ phone.notifyDataConnection(null);
}
if (hasRoamingOn) {
@@ -469,6 +468,34 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
}
/**
+ * Check whether the specified SID and NID pair appears in the HOME SID/NID list
+ * read from NV or SIM.
+ *
+ * @return true if provided sid/nid pair belongs to operator's home network.
+ */
+ private boolean isInHomeSidNid(int sid, int nid) {
+ // if SID/NID is not available, assume this is home network.
+ if (isSidsAllZeros()) return true;
+
+ // length of SID/NID shold be same
+ if (mHomeSystemId.length != mHomeNetworkId.length) return true;
+
+ if (sid == 0) return true;
+
+ for (int i = 0; i < mHomeSystemId.length; i++) {
+ // Use SID only if NID is a reserved value.
+ // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2)
+ if ((mHomeSystemId[i] == sid) &&
+ ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) ||
+ (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) {
+ return true;
+ }
+ }
+ // SID/NID are not in the list. So device is not in home network
+ return false;
+ }
+
+ /**
* Returns OTASP_NOT_NEEDED as its not needed for LTE
*/
@Override
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 24a468a7d2c1..2cf4b8812a37 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -130,8 +130,8 @@ public class CdmaServiceStateTracker extends ServiceStateTracker {
protected String mCurPlmn = null;
protected String mMdn;
- private int mHomeSystemId[] = null;
- private int mHomeNetworkId[] = null;
+ protected int mHomeSystemId[] = null;
+ protected int mHomeNetworkId[] = null;
protected String mMin;
protected String mPrlVersion;
protected boolean mIsMinInfoReady = false;
@@ -999,7 +999,7 @@ public class CdmaServiceStateTracker extends ServiceStateTracker {
}
if (hasCdmaDataConnectionChanged || hasNetworkTypeChanged) {
- phone.notifyDataConnection();
+ phone.notifyDataConnection(null);
}
if (hasRoamingOn) {
@@ -1481,7 +1481,7 @@ public class CdmaServiceStateTracker extends ServiceStateTracker {
}
}
- private boolean isSidsAllZeros() {
+ protected boolean isSidsAllZeros() {
if (mHomeSystemId != null) {
for (int i=0; i < mHomeSystemId.length; i++) {
if (mHomeSystemId[i] != 0) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 93f4b4ea579a..d3645faba86f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -915,7 +915,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
}
if (hasRadioTechnologyChanged) {
- phone.notifyDataConnection(Phone.REASON_NW_TYPE_CHANGED, Phone.APN_TYPE_ALL);
+ phone.notifyDataConnection(Phone.REASON_NW_TYPE_CHANGED);
}
if (hasRoamingOn) {
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index e77646397f9e..9aa70b0e0b60 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -87,8 +87,6 @@ public class ImageProcessingActivity extends Activity
mIsProcessing = false;
}
- // This is a hack to work around an invalidation bug
- mBitmapOut.setPixel(0, 0, 0);
mOutPixelsAllocation.copyTo(mBitmapOut);
mDisplayView.invalidate();
}
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index b09e04b04c5f..fa7cf21627bf 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -68,7 +68,7 @@ import java.util.regex.Pattern;
public class WifiWatchdogStateMachine extends StateMachine {
- private static final boolean VDBG = true; //TODO : Remove this before merge
+ private static final boolean VDBG = false;
private static final boolean DBG = true;
private static final String WWSM_TAG = "WifiWatchdogStateMachine";