summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/accounts/AccountManagerService.java2
-rw-r--r--core/java/android/app/ActivityManager.java44
-rw-r--r--core/java/android/app/ActivityManagerNative.java62
-rw-r--r--core/java/android/app/AliasActivity.java2
-rw-r--r--core/java/android/app/ApplicationContext.java2
-rw-r--r--core/java/android/app/ApplicationErrorReport.java1
-rw-r--r--core/java/android/app/IActivityController.aidl2
-rw-r--r--core/java/android/app/IActivityManager.java14
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java2
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java2
-rw-r--r--core/java/android/bluetooth/package.html90
-rw-r--r--core/java/android/content/Context.java6
-rw-r--r--core/java/android/content/Intent.java94
-rw-r--r--core/java/android/content/IntentFilter.java2
-rw-r--r--core/java/android/content/SyncStorageEngine.java10
-rw-r--r--core/java/android/content/pm/PackageParser.java2
-rw-r--r--core/java/android/content/pm/RegisteredServicesCache.java2
-rw-r--r--core/java/android/content/res/ColorStateList.java2
-rw-r--r--core/java/android/content/res/Resources.java2
-rw-r--r--core/java/android/content/res/StringBlock.java2
-rw-r--r--core/java/android/content/res/TypedArray.java2
-rw-r--r--core/java/android/content/res/XmlBlock.java2
-rw-r--r--core/java/android/gesture/GestureStore.java7
-rwxr-xr-xcore/java/android/gesture/GestureUtilities.java32
-rwxr-xr-xcore/java/android/gesture/Instance.java2
-rw-r--r--core/java/android/gesture/InstanceLearner.java4
-rwxr-xr-xcore/java/android/gesture/Learner.java2
-rwxr-xr-xcore/java/android/inputmethodservice/KeyboardView.java12
-rw-r--r--core/java/android/net/NetworkConnectivityListener.java220
-rw-r--r--core/java/android/net/http/DomainNameChecker.java7
-rw-r--r--core/java/android/os/AsyncTask.java2
-rw-r--r--core/java/android/os/Environment.java16
-rw-r--r--core/java/android/os/FileObserver.java4
-rw-r--r--core/java/android/os/IMountService.aidl40
-rw-r--r--core/java/android/os/IPowerManager.aidl1
-rw-r--r--core/java/android/os/MemoryFile.java13
-rw-r--r--core/java/android/os/MessageQueue.java4
-rw-r--r--core/java/android/os/PowerManager.java3
-rw-r--r--core/java/android/os/RecoverySystem.java418
-rw-r--r--core/java/android/pim/vcard/VCardComposer.java52
-rw-r--r--core/java/android/provider/Calendar.java60
-rw-r--r--core/java/android/provider/Contacts.java66
-rw-r--r--core/java/android/provider/ContactsContract.java88
-rw-r--r--core/java/android/provider/Im.java2358
-rw-r--r--core/java/android/provider/MediaStore.java12
-rw-r--r--core/java/android/provider/Settings.java16
-rw-r--r--core/java/android/server/BluetoothA2dpService.java32
-rw-r--r--core/java/android/server/BluetoothEventLoop.java15
-rw-r--r--core/java/android/server/BluetoothService.java19
-rw-r--r--core/java/android/text/AutoText.java2
-rw-r--r--core/java/android/text/Html.java2
-rw-r--r--core/java/android/text/method/ArrowKeyMovementMethod.java72
-rw-r--r--core/java/android/util/EventLog.java293
-rw-r--r--core/java/android/util/EventLogTags.java56
-rw-r--r--core/java/android/util/Log.java55
-rw-r--r--core/java/android/util/TimeUtils.java2
-rw-r--r--core/java/android/util/XmlPullAttributes.java2
-rw-r--r--core/java/android/view/View.java78
-rw-r--r--core/java/android/view/ViewConfiguration.java4
-rw-r--r--core/java/android/view/ViewDebug.java2
-rw-r--r--core/java/android/view/ViewStub.java8
-rw-r--r--core/java/android/view/WindowManagerPolicy.java13
-rwxr-xr-xcore/java/android/view/WindowOrientationListener.java132
-rw-r--r--core/java/android/webkit/BrowserFrame.java1
-rw-r--r--core/java/android/webkit/CacheManager.java16
-rw-r--r--core/java/android/webkit/CallbackProxy.java39
-rw-r--r--core/java/android/webkit/DebugFlags.java2
-rw-r--r--core/java/android/webkit/LoadListener.java30
-rw-r--r--core/java/android/webkit/PluginFullScreenHolder.java120
-rw-r--r--core/java/android/webkit/ViewManager.java24
-rw-r--r--core/java/android/webkit/WebTextView.java26
-rw-r--r--core/java/android/webkit/WebView.java500
-rw-r--r--core/java/android/webkit/WebViewCore.java132
-rw-r--r--core/java/android/webkit/plugin/FullScreenDrawingModel.java35
-rw-r--r--core/java/android/webkit/plugin/WebkitPlugin.java4
-rw-r--r--core/java/android/widget/AbsListView.java25
-rw-r--r--core/java/android/widget/AbsSeekBar.java37
-rw-r--r--core/java/android/widget/AutoCompleteTextView.java4
-rw-r--r--core/java/android/widget/GridView.java8
-rw-r--r--core/java/android/widget/ImageButton.java2
-rw-r--r--core/java/android/widget/ImageView.java12
-rw-r--r--core/java/android/widget/ListView.java29
-rw-r--r--core/java/android/widget/RelativeLayout.java3
-rw-r--r--core/java/android/widget/RemoteViews.java40
-rw-r--r--core/java/android/widget/SimpleAdapter.java18
-rw-r--r--core/java/android/widget/SimpleCursorAdapter.java31
-rw-r--r--core/java/com/android/internal/database/ArrayListCursor.java171
-rw-r--r--core/java/com/android/internal/net/DbSSLSessionCache.java289
-rw-r--r--core/java/com/android/internal/os/LoggingPrintStream.java81
-rw-r--r--core/java/com/android/internal/os/PowerProfile.java2
-rw-r--r--core/java/com/android/internal/os/RecoverySystem.java143
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java82
-rw-r--r--core/java/com/android/internal/util/FastXmlSerializer.java365
-rw-r--r--core/java/com/android/internal/util/XmlUtils.java796
-rw-r--r--core/java/com/android/internal/widget/VerticalTextSpinner.java467
-rw-r--r--core/java/com/google/android/net/NetworkStatsEntity.java84
-rw-r--r--core/java/com/google/android/net/SSLClientSessionCacheFactory.java62
-rw-r--r--core/java/com/google/android/net/UrlRules.java236
-rw-r--r--core/java/com/google/android/util/SimplePullParser.java391
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/android/graphics/Typeface.cpp2
-rw-r--r--core/jni/android/opengl/util.cpp309
-rw-r--r--core/jni/android_hardware_Camera.cpp2
-rw-r--r--core/jni/android_os_MemoryFile.cpp8
-rw-r--r--core/jni/android_server_BluetoothA2dpService.cpp38
-rw-r--r--core/jni/android_text_format_Time.cpp46
-rw-r--r--core/jni/android_util_AssetManager.cpp1
-rw-r--r--core/jni/android_util_EventLog.cpp285
-rw-r--r--core/res/Android.mk2
-rw-r--r--core/res/AndroidManifest.xml40
-rw-r--r--core/res/res/anim/lock_screen_enter.xml24
-rw-r--r--core/res/res/anim/lock_screen_exit.xml3
-rw-r--r--core/res/res/drawable-hdpi/pickerbox_background.pngbin1131 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/pickerbox_selected.9.pngbin2129 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/pickerbox_unselected.9.pngbin1419 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/pickerbox_background.pngbin4226 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/pickerbox_selected.9.pngbin2155 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/pickerbox_unselected.9.pngbin1474 -> 0 bytes
-rw-r--r--core/res/res/drawable/pickerbox.xml21
-rw-r--r--core/res/res/layout/keyguard_screen_sim_pin_portrait.xml93
-rw-r--r--core/res/res/values/strings.xml18
-rw-r--r--core/res/res/values/styles.xml1
122 files changed, 2944 insertions, 6832 deletions
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 54e0375..fc72f9a 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -155,7 +155,7 @@ public class AccountManagerService
new AtomicReference<AccountManagerService>();
private static final boolean isDebuggableMonkeyBuild =
- SystemProperties.getBoolean("ro.monkey", false)
+ SystemProperties.getBoolean("monkey.running", false)
&& SystemProperties.getBoolean("ro.debuggable", false);
private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 676d6d5..930ab65 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -606,7 +606,7 @@ public class ActivityManager {
public int uid;
/**
- * The tag that was provided when the process crashed.
+ * The activity name associated with the error, if known. May be null.
*/
public String tag;
@@ -891,6 +891,38 @@ public class ActivityManager {
}
/**
+ * @deprecated This is now just a wrapper for
+ * {@link #killBackgroundProcesses(String)}; the previous behavior here
+ * is no longer available to applications because it allows them to
+ * break other applications by removing their alarms, stopping their
+ * services, etc.
+ */
+ @Deprecated
+ public void restartPackage(String packageName) {
+ killBackgroundProcesses(packageName);
+ }
+
+ /**
+ * Have the system immediately kill all background processes associated
+ * with the given package. This is the same as the kernel killing those
+ * processes to reclaim memory; the system will take care of restarting
+ * these processes in the future as needed.
+ *
+ * <p>You must hold the permission
+ * {@link android.Manifest.permission#KILL_BACKGROUND_PROCESSES} to be able to
+ * call this method.
+ *
+ * @param packageName The name of the package whose processes are to
+ * be killed.
+ */
+ public void killBackgroundProcesses(String packageName) {
+ try {
+ ActivityManagerNative.getDefault().killBackgroundProcesses(packageName);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Have the system perform a force stop of everything associated with
* the given application package. All processes that share its uid
* will be killed, all services it has running stopped, all activities
@@ -899,14 +931,18 @@ public class ActivityManager {
* be stopped, notifications removed, etc.
*
* <p>You must hold the permission
- * {@link android.Manifest.permission#RESTART_PACKAGES} to be able to
+ * {@link android.Manifest.permission#FORCE_STOP_PACKAGES} to be able to
* call this method.
*
* @param packageName The name of the package to be stopped.
+ *
+ * @hide This is not available to third party applications due to
+ * it allowing them to break other applications by stopping their
+ * services, removing their alarms, etc.
*/
- public void restartPackage(String packageName) {
+ public void forceStopPackage(String packageName) {
try {
- ActivityManagerNative.getDefault().restartPackage(packageName);
+ ActivityManagerNative.getDefault().forceStopPackage(packageName);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index a0498aa..09b88ee 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -979,13 +979,23 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
- case HANDLE_APPLICATION_ERROR_TRANSACTION: {
+ case HANDLE_APPLICATION_CRASH_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder app = data.readStrongBinder();
+ ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data);
+ handleApplicationCrash(app, ci);
+ reply.writeNoException();
+ return true;
+ }
+
+ case HANDLE_APPLICATION_WTF_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder app = data.readStrongBinder();
String tag = data.readString();
ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data);
- handleApplicationError(app, tag, ci);
+ boolean res = handleApplicationWtf(app, tag, ci);
reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
return true;
}
@@ -997,10 +1007,18 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
- case RESTART_PACKAGE_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
+ case KILL_BACKGROUND_PROCESSES_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
String packageName = data.readString();
- restartPackage(packageName);
+ killBackgroundProcesses(packageName);
+ reply.writeNoException();
+ return true;
+ }
+
+ case FORCE_STOP_PACKAGE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String packageName = data.readString();
+ forceStopPackage(packageName);
reply.writeNoException();
return true;
}
@@ -2337,7 +2355,20 @@ class ActivityManagerProxy implements IActivityManager
/* this base class version is never called */
return true;
}
- public void handleApplicationError(IBinder app, String tag,
+ public void handleApplicationCrash(IBinder app,
+ ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(app);
+ crashInfo.writeToParcel(data, 0);
+ mRemote.transact(HANDLE_APPLICATION_CRASH_TRANSACTION, data, reply, 0);
+ reply.readException();
+ reply.recycle();
+ data.recycle();
+ }
+ public boolean handleApplicationWtf(IBinder app, String tag,
ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -2346,10 +2377,12 @@ class ActivityManagerProxy implements IActivityManager
data.writeStrongBinder(app);
data.writeString(tag);
crashInfo.writeToParcel(data, 0);
- mRemote.transact(HANDLE_APPLICATION_ERROR_TRANSACTION, data, reply, 0);
+ mRemote.transact(HANDLE_APPLICATION_WTF_TRANSACTION, data, reply, 0);
reply.readException();
+ boolean res = reply.readInt() != 0;
reply.recycle();
data.recycle();
+ return res;
}
public void signalPersistentProcesses(int sig) throws RemoteException {
@@ -2363,12 +2396,23 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
- public void restartPackage(String packageName) throws RemoteException {
+ public void killBackgroundProcesses(String packageName) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(packageName);
+ mRemote.transact(KILL_BACKGROUND_PROCESSES_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ public void forceStopPackage(String packageName) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(packageName);
- mRemote.transact(RESTART_PACKAGE_TRANSACTION, data, reply, 0);
+ mRemote.transact(FORCE_STOP_PACKAGE_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
diff --git a/core/java/android/app/AliasActivity.java b/core/java/android/app/AliasActivity.java
index 4f91e02..7527a5b 100644
--- a/core/java/android/app/AliasActivity.java
+++ b/core/java/android/app/AliasActivity.java
@@ -26,7 +26,7 @@ import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Xml;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
import java.io.IOException;
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index b3d16e9..d89b877 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -17,7 +17,7 @@
package android.app;
import com.android.internal.policy.PolicyManager;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
import com.google.android.collect.Maps;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index e89b3ad0..a4b692f 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -195,6 +195,7 @@ public class ApplicationErrorReport implements Parcelable {
StringWriter sw = new StringWriter();
tr.printStackTrace(new PrintWriter(sw));
stackTrace = sw.toString();
+ exceptionMessage = tr.getMessage();
// Populate fields with the "root cause" exception
while (tr.getCause() != null) {
diff --git a/core/java/android/app/IActivityController.aidl b/core/java/android/app/IActivityController.aidl
index 804dd61..c76a517 100644
--- a/core/java/android/app/IActivityController.aidl
+++ b/core/java/android/app/IActivityController.aidl
@@ -44,7 +44,7 @@ interface IActivityController
* it immediately.
*/
boolean appCrashed(String processName, int pid,
- String tag, String shortMsg, String longMsg,
+ String shortMsg, String longMsg,
long timeMillis, String stackTrace);
/**
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index c890c4c..016d465 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -216,7 +216,8 @@ public interface IActivityManager extends IInterface {
public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) throws RemoteException;
- public void restartPackage(final String packageName) throws RemoteException;
+ public void killBackgroundProcesses(final String packageName) throws RemoteException;
+ public void forceStopPackage(final String packageName) throws RemoteException;
// Note: probably don't want to allow applications access to these.
public void goingToSleep() throws RemoteException;
@@ -242,8 +243,9 @@ public interface IActivityManager extends IInterface {
// Special low-level communication with activity manager.
public void startRunning(String pkg, String cls, String action,
String data) throws RemoteException;
-
- public void handleApplicationError(IBinder app, String tag,
+ public void handleApplicationCrash(IBinder app,
+ ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
+ public boolean handleApplicationWtf(IBinder app, String tag,
ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
/*
@@ -349,7 +351,7 @@ public interface IActivityManager extends IInterface {
// Please keep these transaction codes the same -- they are also
// sent by C++ code.
int START_RUNNING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
- int HANDLE_APPLICATION_ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
+ int HANDLE_APPLICATION_CRASH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
int START_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
int UNHANDLED_BACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
int OPEN_CONTENT_URI_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
@@ -423,7 +425,7 @@ public interface IActivityManager extends IInterface {
int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+75;
int GET_PROCESSES_IN_ERROR_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+76;
int CLEAR_APP_DATA_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+77;
- int RESTART_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
+ int FORCE_STOP_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80;
int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81;
@@ -446,4 +448,6 @@ public interface IActivityManager extends IInterface {
int KILL_APPLICATION_PROCESS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+98;
int START_ACTIVITY_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+99;
int OVERRIDE_PENDING_TRANSITION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+100;
+ int HANDLE_APPLICATION_WTF_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+101;
+ int KILL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+102;
}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index fda9b81..7e5f858 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -83,6 +83,8 @@ public final class BluetoothA2dp {
/** Default priority for a2dp devices that should not allow incoming
* connections */
public static final int PRIORITY_OFF = 0;
+ /** Default priority when not set or when the device is unpaired */
+ public static final int PRIORITY_UNDEFINED = -1;
private final IBluetoothA2dp mService;
private final Context mContext;
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 5eb655a..b792965 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -109,6 +109,8 @@ public final class BluetoothHeadset {
/** Default priority for headsets that should not be auto-connected
* and not allow incoming connections. */
public static final int PRIORITY_OFF = 0;
+ /** Default priority when not set or when the device is unpaired */
+ public static final int PRIORITY_UNDEFINED = -1;
/** The voice dialer 'works' but the user experience is poor. The voice
* recognizer has trouble dealing with the 8kHz SCO signal, and it still
diff --git a/core/java/android/bluetooth/package.html b/core/java/android/bluetooth/package.html
index 4f0755e..5ff240c 100644
--- a/core/java/android/bluetooth/package.html
+++ b/core/java/android/bluetooth/package.html
@@ -12,96 +12,16 @@ devices, connecting with devices, and managing data transfer between devices.
<li>Transfer data to and from other devices</li>
</ul>
-<p class="note"><strong>Note:</strong>
+<p>
To perform Bluetooth communication using these APIs, an application must
declare the {@link android.Manifest.permission#BLUETOOTH} permission. Some
-additional functionality, such as requesting device discovery and
-pairing also requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+additional functionality, such as requesting device discovery,
+also requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
permission.
</p>
-<h3>Overview</h3>
-
-<p>Here's a basic introduction to the Bluetooth classes:</p>
-<dl>
- <dt>{@link android.bluetooth.BluetoothAdapter}</dt>
- <dd>This represents the local Bluetooth adapter, which is essentially the
- entry-point to performing any interaction with Bluetooth. With it, you can
- discover other Bluetooth devices, query a list of bonded (paired) devices,
- initialize a {@link android.bluetooth.BluetoothDevice} using a known MAC
- address, and create a {@link android.bluetooth.BluetoothServerSocket} to
- listen for communications from other devices.</dd>
-
- <dt>{@link android.bluetooth.BluetoothDevice}</dt>
- <dd>This represents a remote Bluetooth device. Use this to request a
- connection with a remote device through a
- {@link android.bluetooth.BluetoothSocket}
- or query information about the device such as its name, address, class, and
- bonding state.</dd>
-
- <dt>{@link android.bluetooth.BluetoothSocket}</dt>
- <dd>This represents the interface for a Bluetooth socket
- (similar to a TCP client-side {@link java.net.Socket}). This is the
- connection point that allows an app to transfer data with another Bluetooth
- device via {@link java.io.InputStream} and {@link java.io.OutputStream}.</dd>
- <dt>{@link android.bluetooth.BluetoothServerSocket}</dt>
-
- <dd>This represents an open server socket that listens for incoming requests
- (similar to a TCP server-side {@link java.net.ServerSocket}).
- When attempting to connect two Android devices, one device will need to open
- a server socket with this class. When a connection is accepted, a new
- {@link android.bluetooth.BluetoothSocket} will be returned,
- which can be used to manage the connection and transfer data.</dd>
-
- <dt>{@link android.bluetooth.BluetoothClass}</dt>
- <dd>This represents the Bluetooth class for a device which describes general
- characteristics and capabilities of a device. This class and its subclasses
- don't provide any actual functionality. The sub-classes are entirely composed
- of constants for the device and service class definitions.</dd>
-</dl>
-
-
-<h3>Example Procedure</h3>
-
-<p>For example, here's an pseudo-code procedure for discovering and
-connecting a remote device, and transfering data:</p>
-
-<ol>
- <li>Register a {@link android.content.BroadcastReceiver} that accepts the
- {@link android.bluetooth.BluetoothDevice#ACTION_FOUND} Intent.</li>
- <li>Call {@link android.bluetooth.BluetoothAdapter#getDefaultAdapter} to
- retrieve the Android system's local
- {@link android.bluetooth.BluetoothAdapter}.</li>
- <li>Call {@link android.bluetooth.BluetoothAdapter#startDiscovery()
- BluetoothAdapter.startDiscovery()} to scan for local devices. This is where
- the BroadcastReceiver comes in; Android now scans for devices and will
- broadcast the {@link android.bluetooth.BluetoothDevice#ACTION_FOUND} Intent
- for each remote device discovered. The
- {@link android.content.BroadcastReceiver}
- you created will receive each Intent.</li>
- <li>The {@link android.bluetooth.BluetoothDevice#ACTION_FOUND} Intent
- includes the {@link android.bluetooth.BluetoothDevice#EXTRA_DEVICE}
- Parcelable extra, which is a {@link android.bluetooth.BluetoothDevice}
- object. Extract this from the Intent and call
- {@link android.bluetooth.BluetoothDevice#createRfcommSocketToServiceRecord(java.util.UUID)
- BluetoothDevice.createRfcommSocketToServiceRecord()}
- to open a {@link android.bluetooth.BluetoothSocket} with a chosen
- remote device.</li>
- <li>Call {@link android.bluetooth.BluetoothSocket#connect()
- BluetoothSocket.connect()} to connect with the remote device.</li>
- <li>When successfully connected, call
- {@link android.bluetooth.BluetoothSocket#getInputStream()
- BluetoothSocket.getInputStream()} and/or
- {@link android.bluetooth.BluetoothSocket#getOutputStream()
- BluetoothSocket.getOutputStream()} to retreive an
- {@link java.io.InputStream} and {@link java.io.OutputStream}, respectively,
- which are hooked into the socket.</li>
- <li>Use {@link java.io.InputStream#read(byte[]) InputStream.read()} and
- {@link java.io.OutputStream#write(byte[]) OutputStream.write()} to transfer
- data.</li>
-</ol>
-
-
+<p>For a detailed guide to using the Bluetooth APIs, see the <a
+href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth Dev Guide topic</a>.</p>
<p class="note"><strong>Note:</strong>
Not all Android devices are guaranteed to have Bluetooth functionality.</p>
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2ab5357..0fafe5d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1314,7 +1314,7 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
- * {@blink android.appwidget.AppWidgetManager} for accessing AppWidgets.
+ * {@link android.appwidget.AppWidgetManager} for accessing AppWidgets.
*
* @hide
* @see #getSystemService
@@ -1323,7 +1323,7 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve an
- * {@blink android.backup.IBackupManager IBackupManager} for communicating
+ * {@link android.backup.IBackupManager IBackupManager} for communicating
* with the backup mechanism.
* @hide
*
@@ -1333,7 +1333,7 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
- * {@blink android.os.DropBox DropBox} instance for recording
+ * {@link android.os.DropBoxManager} instance for recording
* diagnostic logs.
* @see #getSystemService
*/
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d784759..bf37b62 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -34,7 +34,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
import java.io.IOException;
import java.io.Serializable;
@@ -575,7 +575,7 @@ import java.util.Set;
* {@link #setFlags} and {@link #addFlags}. See {@link #setFlags} for a list
* of all possible flags.
*/
-public class Intent implements Parcelable {
+public class Intent implements Parcelable, Cloneable {
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent activity actions (see action variable).
@@ -1130,7 +1130,7 @@ public class Intent implements Parcelable {
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
-
+
/**
* Activity Action: Setup wizard to launch after a platform update. This
* activity should have a string meta-data field associated with it,
@@ -1144,7 +1144,7 @@ public class Intent implements Parcelable {
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
-
+
/**
* A string associated with a {@link #ACTION_UPGRADE_SETUP} activity
* describing the last run version of the platform that was setup.
@@ -1158,7 +1158,7 @@ public class Intent implements Parcelable {
/**
* Broadcast Action: Sent after the screen turns off.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1166,7 +1166,7 @@ public class Intent implements Parcelable {
public static final String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
/**
* Broadcast Action: Sent after the screen turns on.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1176,7 +1176,7 @@ public class Intent implements Parcelable {
/**
* Broadcast Action: Sent when the user is present after device wakes up (e.g when the
* keyguard is gone).
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1189,7 +1189,7 @@ public class Intent implements Parcelable {
* in manifests, only by exlicitly registering for it with
* {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
* Context.registerReceiver()}.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1210,7 +1210,7 @@ public class Intent implements Parcelable {
* <ul>
* <li><em>time-zone</em> - The java.util.TimeZone.getID() value identifying the new time zone.</li>
* </ul>
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1238,7 +1238,7 @@ public class Intent implements Parcelable {
* such as installing alarms. You must hold the
* {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission
* in order to receive this broadcast.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1254,7 +1254,7 @@ public class Intent implements Parcelable {
* Broadcast Action: Trigger the download and eventual installation
* of a package.
* <p>Input: {@link #getData} is the URI of the package file to download.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1270,7 +1270,7 @@ public class Intent implements Parcelable {
* <li> {@link #EXTRA_REPLACING} is set to true if this is following
* an {@link #ACTION_PACKAGE_REMOVED} broadcast for the same package.
* </ul>
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1284,7 +1284,7 @@ public class Intent implements Parcelable {
* <ul>
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the new package.
* </ul>
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1302,7 +1302,7 @@ public class Intent implements Parcelable {
* <li> {@link #EXTRA_REPLACING} is set to true if this will be followed
* by an {@link #ACTION_PACKAGE_ADDED} broadcast for the same package.
* </ul>
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1319,7 +1319,7 @@ public class Intent implements Parcelable {
* <li> {@link #EXTRA_DONT_KILL_APP} containing boolean field to override the
* default action of restarting the application.
* </ul>
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1335,7 +1335,7 @@ public class Intent implements Parcelable {
* <ul>
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
* </ul>
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1350,7 +1350,7 @@ public class Intent implements Parcelable {
* <ul>
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
* </ul>
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1359,7 +1359,7 @@ public class Intent implements Parcelable {
/**
* Broadcast Action: A user ID has been removed from the system. The user
* ID number is stored in the extra data under {@link #EXTRA_UID}.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1380,13 +1380,13 @@ public class Intent implements Parcelable {
* application to make sure it sees the new changes. Some system code that
* can not be restarted will need to watch for this action and handle it
* appropriately.
- *
+ *
* <p class="note">
* You can <em>not</em> receive this through components declared
* in manifests, only by explicitly registering for it with
* {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
* Context.registerReceiver()}.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*
@@ -1396,7 +1396,7 @@ public class Intent implements Parcelable {
public static final String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
/**
* Broadcast Action: The current device's locale has changed.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1417,7 +1417,7 @@ public class Intent implements Parcelable {
* and {@link #ACTION_POWER_DISCONNECTED} for distinct battery-related
* broadcasts that are sent and can be received through manifest
* receivers.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1426,7 +1426,7 @@ public class Intent implements Parcelable {
/**
* Broadcast Action: Indicates low battery condition on the device.
* This broadcast corresponds to the "Low battery warning" system dialog.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1436,7 +1436,7 @@ public class Intent implements Parcelable {
* Broadcast Action: Indicates the battery is now okay after being low.
* This will be sent after {@link #ACTION_BATTERY_LOW} once the battery has
* gone back up to an okay state.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1448,7 +1448,7 @@ public class Intent implements Parcelable {
* Unlike ACTION_BATTERY_CHANGED, applications will be woken for this and so do not have to
* stay active to receive this notification. This action can be used to implement actions
* that wait until power is available to trigger.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1460,7 +1460,7 @@ public class Intent implements Parcelable {
* Unlike ACTION_BATTERY_CHANGED, applications will be woken for this and so do not have to
* stay active to receive this notification. This action can be used to implement actions
* that wait until power is available to trigger.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1473,7 +1473,7 @@ public class Intent implements Parcelable {
* off, not sleeping). Once the broadcast is complete, the final shutdown
* will proceed and all unsaved data lost. Apps will not normally need
* to handle this, since the foreground activity will be paused as well.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1493,7 +1493,7 @@ public class Intent implements Parcelable {
/**
* Broadcast Action: A sticky broadcast that indicates low memory
* condition on the device
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1501,7 +1501,7 @@ public class Intent implements Parcelable {
public static final String ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW";
/**
* Broadcast Action: Indicates low memory condition on the device no longer exists
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1668,7 +1668,7 @@ public class Intent implements Parcelable {
* then cell radio and possibly other radios such as bluetooth or WiFi may have also been
* turned off</li>
* </ul>
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1750,7 +1750,7 @@ public class Intent implements Parcelable {
* <p>You must hold the
* {@link android.Manifest.permission#PROCESS_OUTGOING_CALLS}
* permission to receive this Intent.</p>
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -1761,7 +1761,7 @@ public class Intent implements Parcelable {
/**
* Broadcast Action: Have the device reboot. This is only for use by
* system code.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -2112,7 +2112,7 @@ public class Intent implements Parcelable {
* indicate that the dock should take over the home key when it is active.
*/
public static final String METADATA_DOCK_HOME = "android.dock_home";
-
+
/**
* Used as a parcelable extra field in {@link #ACTION_APP_ERROR}, containing
* the bug report.
@@ -2406,7 +2406,7 @@ public class Intent implements Parcelable {
* the new broadcast (and receivers associated with it) will replace the
* existing one in the pending broadcast list, remaining at the same
* position in the list.
- *
+ *
* <p>This flag is most typically used with sticky broadcasts, which
* only care about delivering the most recent values of the broadcast
* to their receivers.
@@ -2440,7 +2440,7 @@ public class Intent implements Parcelable {
public static final int IMMUTABLE_FLAGS =
FLAG_GRANT_READ_URI_PERMISSION
| FLAG_GRANT_WRITE_URI_PERMISSION;
-
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// toUri() and parseUri() options.
@@ -2454,7 +2454,7 @@ public class Intent implements Parcelable {
* VIEW action for that raw URI.
*/
public static final int URI_INTENT_SCHEME = 1<<0;
-
+
// ---------------------------------------------------------------------
private String mAction;
@@ -2613,7 +2613,7 @@ public class Intent implements Parcelable {
public static Intent getIntent(String uri) throws URISyntaxException {
return parseUri(uri, 0);
}
-
+
/**
* Create an intent from a URI. This URI may encode the action,
* category, and other intent fields, if it was returned by
@@ -2632,7 +2632,7 @@ public class Intent implements Parcelable {
* @throws URISyntaxException Throws URISyntaxError if the basic URI syntax
* it bad (as parsed by the Uri class) or the Intent data within the
* URI is invalid.
- *
+ *
* @see #toUri
*/
public static Intent parseUri(String uri, int flags) throws URISyntaxException {
@@ -2650,7 +2650,7 @@ public class Intent implements Parcelable {
return intent;
}
}
-
+
// simple case
i = uri.lastIndexOf("#");
if (i == -1) return new Intent(ACTION_VIEW, Uri.parse(uri));
@@ -2742,7 +2742,7 @@ public class Intent implements Parcelable {
data = scheme + ':' + data;
}
}
-
+
if (data.length() > 0) {
try {
intent.mData = Uri.parse(data);
@@ -2751,7 +2751,7 @@ public class Intent implements Parcelable {
}
}
}
-
+
return intent;
} catch (IndexOutOfBoundsException e) {
@@ -2902,7 +2902,7 @@ public class Intent implements Parcelable {
} else {
intent.mData = Uri.parse(uri);
}
-
+
if (intent.mAction == null) {
// By default, if no action is specified, then use VIEW.
intent.mAction = ACTION_VIEW;
@@ -5127,13 +5127,13 @@ public class Intent implements Parcelable {
* used with {@link Uri#parse Uri.parse(String)}. The URI contains the
* Intent's data as the base URI, with an additional fragment describing
* the action, categories, type, flags, package, component, and extras.
- *
+ *
* <p>You can convert the returned string back to an Intent with
* {@link #getIntent}.
- *
+ *
* @param flags Additional operating flags. Either 0 or
* {@link #URI_INTENT_SCHEME}.
- *
+ *
* @return Returns a URI encoding URI string describing the entire contents
* of the Intent.
*/
@@ -5157,13 +5157,13 @@ public class Intent implements Parcelable {
data = data.substring(i+1);
break;
}
-
+
// No scheme.
break;
}
}
uri.append(data);
-
+
} else if ((flags&URI_INTENT_SCHEME) != 0) {
uri.append("intent:");
}
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 365f269..023c024 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -34,7 +34,7 @@ import android.util.AndroidException;
import android.util.Config;
import android.util.Log;
import android.util.Printer;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
/**
* Structured description of Intent values to be matched. An IntentFilter can
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index b6bb7db..4c53201 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -16,6 +16,10 @@
package android.content;
+import com.android.internal.os.AtomicFile;
+import com.android.internal.util.ArrayUtils;
+import com.android.common.FastXmlSerializer;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -37,10 +41,6 @@ import android.util.Log;
import android.util.SparseArray;
import android.util.Xml;
-import com.android.internal.os.AtomicFile;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
-
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -512,7 +512,7 @@ public class SyncStorageEngine extends Handler {
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.pending = true;
- status.initialize = op.extras != null &&
+ status.initialize = op.extras != null &&
op.extras.containsKey(ContentResolver.SYNC_EXTRAS_INITIALIZE) &&
op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 48d1add..ad99f54 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -35,7 +35,7 @@ import android.util.Config;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
import java.io.File;
import java.io.IOException;
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index b39a67d..b819fa0 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -43,7 +43,7 @@ import java.io.IOException;
import java.io.FileInputStream;
import com.android.internal.os.AtomicFile;
-import com.android.internal.util.FastXmlSerializer;
+import com.android.common.FastXmlSerializer;
import com.google.android.collect.Maps;
import com.google.android.collect.Lists;
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 453a83d..70baaef 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -44,7 +44,7 @@ import java.util.Arrays;
* &lt;selector xmlns:android="http://schemas.android.com/apk/res/android"&gt;
* &lt;item android:state_focused="true" android:color="@color/testcolor1"/&gt;
* &lt;item android:state_pressed="true" android:state_enabled="false" android:color="@color/testcolor2" /&gt;
- * &lt;item android:state_enabled="false" android:colore="@color/testcolor3" /&gt;
+ * &lt;item android:state_enabled="false" android:color="@color/testcolor3" /&gt;
* &lt;item android:state_active="true" android:color="@color/testcolor4" /&gt;
* &lt;item android:color="@color/testcolor5"/&gt;
* &lt;/selector&gt;
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 1c0ed36..e4fc259 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -17,7 +17,7 @@
package android.content.res;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java
index 8fb82be..2411177 100644
--- a/core/java/android/content/res/StringBlock.java
+++ b/core/java/android/content/res/StringBlock.java
@@ -24,7 +24,7 @@ import android.util.SparseArray;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
/**
* Conveniences for retrieving data out of a compiled string resource.
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 016ee7f..8f0003b 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -5,7 +5,7 @@ import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
import java.util.Arrays;
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index 6336678..f800232 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -17,7 +17,7 @@
package android.content.res;
import android.util.TypedValue;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/gesture/GestureStore.java b/core/java/android/gesture/GestureStore.java
index 5f1a445..11a94d1 100644
--- a/core/java/android/gesture/GestureStore.java
+++ b/core/java/android/gesture/GestureStore.java
@@ -65,7 +65,12 @@ public class GestureStore {
// ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures
public static final int ORIENTATION_INVARIANT = 1;
+ // at most 2 directions can be recognized
public static final int ORIENTATION_SENSITIVE = 2;
+ // at most 4 directions can be recognized
+ static final int ORIENTATION_SENSITIVE_4 = 4;
+ // at most 8 directions can be recognized
+ static final int ORIENTATION_SENSITIVE_8 = 8;
private static final short FILE_FORMAT_VERSION = 1;
@@ -131,7 +136,7 @@ public class GestureStore {
public ArrayList<Prediction> recognize(Gesture gesture) {
Instance instance = Instance.createInstance(mSequenceType,
mOrientationStyle, gesture, null);
- return mClassifier.classify(mSequenceType, instance.vector);
+ return mClassifier.classify(mSequenceType, mOrientationStyle, instance.vector);
}
/**
diff --git a/core/java/android/gesture/GestureUtilities.java b/core/java/android/gesture/GestureUtilities.java
index 40d7029..f1dcd89 100755
--- a/core/java/android/gesture/GestureUtilities.java
+++ b/core/java/android/gesture/GestureUtilities.java
@@ -366,6 +366,38 @@ final class GestureUtilities {
}
return Math.acos(sum);
}
+
+ /**
+ * Calculate the "minimum" cosine distance between two instances
+ *
+ * @param vector1
+ * @param vector2
+ * @param numOrientations the maximum number of orientation allowed
+ * @return the distance between the two instances (between 0 and Math.PI)
+ */
+ static double minimumCosineDistance(float[] vector1, float[] vector2, int numOrientations) {
+ final int len = vector1.length;
+ double a = 0;
+ double b = 0;
+ for (int i = 0; i < len; i += 2) {
+ a += vector1[i] * vector2[i] + vector1[i + 1] * vector2[i + 1];
+ b += vector1[i] * vector2[i + 1] - vector1[i + 1] * vector2[i];
+ }
+ if (a != 0) {
+ final double tan = b/a;
+ final double angle = Math.atan(tan);
+ if (numOrientations > 2 && Math.abs(angle) >= Math.PI / numOrientations) {
+ return Math.acos(a);
+ } else {
+ final double cosine = Math.cos(angle);
+ final double sine = cosine * tan;
+ return Math.acos(a * cosine + b * sine);
+ }
+ } else {
+ return Math.PI / 2;
+ }
+ }
+
static OrientedBoundingBox computeOrientedBoundingBox(ArrayList<GesturePoint> pts) {
GestureStroke stroke = new GestureStroke(pts);
diff --git a/core/java/android/gesture/Instance.java b/core/java/android/gesture/Instance.java
index ef208ac..68a2985 100755
--- a/core/java/android/gesture/Instance.java
+++ b/core/java/android/gesture/Instance.java
@@ -94,7 +94,7 @@ class Instance {
float orientation = (float)Math.atan2(pts[1] - center[1], pts[0] - center[0]);
float adjustment = -orientation;
- if (orientationType == GestureStore.ORIENTATION_SENSITIVE) {
+ if (orientationType != GestureStore.ORIENTATION_INVARIANT) {
int count = ORIENTATIONS.length;
for (int i = 0; i < count; i++) {
float delta = ORIENTATIONS[i] - orientation;
diff --git a/core/java/android/gesture/InstanceLearner.java b/core/java/android/gesture/InstanceLearner.java
index b93b76f..9987e69 100644
--- a/core/java/android/gesture/InstanceLearner.java
+++ b/core/java/android/gesture/InstanceLearner.java
@@ -41,7 +41,7 @@ class InstanceLearner extends Learner {
};
@Override
- ArrayList<Prediction> classify(int sequenceType, float[] vector) {
+ ArrayList<Prediction> classify(int sequenceType, int orientationType, float[] vector) {
ArrayList<Prediction> predictions = new ArrayList<Prediction>();
ArrayList<Instance> instances = getInstances();
int count = instances.size();
@@ -53,7 +53,7 @@ class InstanceLearner extends Learner {
}
double distance;
if (sequenceType == GestureStore.SEQUENCE_SENSITIVE) {
- distance = GestureUtilities.cosineDistance(sample.vector, vector);
+ distance = GestureUtilities.minimumCosineDistance(sample.vector, vector, orientationType);
} else {
distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector);
}
diff --git a/core/java/android/gesture/Learner.java b/core/java/android/gesture/Learner.java
index feacde5..60997e0 100755
--- a/core/java/android/gesture/Learner.java
+++ b/core/java/android/gesture/Learner.java
@@ -79,5 +79,5 @@ abstract class Learner {
instances.removeAll(toDelete);
}
- abstract ArrayList<Prediction> classify(int gestureType, float[] vector);
+ abstract ArrayList<Prediction> classify(int sequenceType, int orientationType, float[] vector);
}
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 76131fc..b0c3909 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -1118,6 +1118,11 @@ public class KeyboardView extends View implements View.OnClickListener {
if (action == MotionEvent.ACTION_DOWN) mSwipeTracker.clear();
mSwipeTracker.addMovement(me);
+ // Ignore all motion events until a DOWN.
+ if (mAbortKey && action != MotionEvent.ACTION_DOWN) {
+ return true;
+ }
+
if (mGestureDetector.onTouchEvent(me)) {
showPreview(NOT_A_KEY);
mHandler.removeMessages(MSG_REPEAT);
@@ -1150,9 +1155,14 @@ public class KeyboardView extends View implements View.OnClickListener {
mKeys[keyIndex].codes[0] : 0);
if (mCurrentKey >= 0 && mKeys[mCurrentKey].repeatable) {
mRepeatKeyIndex = mCurrentKey;
- repeatKey();
Message msg = mHandler.obtainMessage(MSG_REPEAT);
mHandler.sendMessageDelayed(msg, REPEAT_START_DELAY);
+ repeatKey();
+ // Delivering the key could have caused an abort
+ if (mAbortKey) {
+ mRepeatKeyIndex = NOT_A_KEY;
+ break;
+ }
}
if (mCurrentKey != NOT_A_KEY) {
Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me);
diff --git a/core/java/android/net/NetworkConnectivityListener.java b/core/java/android/net/NetworkConnectivityListener.java
deleted file mode 100644
index 858fc77..0000000
--- a/core/java/android/net/NetworkConnectivityListener.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.Iterator;
-
-/**
- * A wrapper for a broadcast receiver that provides network connectivity
- * state information, independent of network type (mobile, Wi-Fi, etc.).
- * {@hide}
- */
-public class NetworkConnectivityListener {
- private static final String TAG = "NetworkConnectivityListener";
- private static final boolean DBG = false;
-
- private Context mContext;
- private HashMap<Handler, Integer> mHandlers = new HashMap<Handler, Integer>();
- private State mState;
- private boolean mListening;
- private String mReason;
- private boolean mIsFailover;
-
- /** Network connectivity information */
- private NetworkInfo mNetworkInfo;
-
- /**
- * In case of a Disconnect, the connectivity manager may have
- * already established, or may be attempting to establish, connectivity
- * with another network. If so, {@code mOtherNetworkInfo} will be non-null.
- */
- private NetworkInfo mOtherNetworkInfo;
-
- private ConnectivityBroadcastReceiver mReceiver;
-
- private class ConnectivityBroadcastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
-
- if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
- mListening == false) {
- Log.w(TAG, "onReceived() called with " + mState.toString() + " and " + intent);
- return;
- }
-
- boolean noConnectivity =
- intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
-
- if (noConnectivity) {
- mState = State.NOT_CONNECTED;
- } else {
- mState = State.CONNECTED;
- }
-
- mNetworkInfo = (NetworkInfo)
- intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
- mOtherNetworkInfo = (NetworkInfo)
- intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
-
- mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
- mIsFailover =
- intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
-
- if (DBG) {
- Log.d(TAG, "onReceive(): mNetworkInfo=" + mNetworkInfo + " mOtherNetworkInfo = "
- + (mOtherNetworkInfo == null ? "[none]" : mOtherNetworkInfo +
- " noConn=" + noConnectivity) + " mState=" + mState.toString());
- }
-
- // Notifiy any handlers.
- Iterator<Handler> it = mHandlers.keySet().iterator();
- while (it.hasNext()) {
- Handler target = it.next();
- Message message = Message.obtain(target, mHandlers.get(target));
- target.sendMessage(message);
- }
- }
- };
-
- public enum State {
- UNKNOWN,
-
- /** This state is returned if there is connectivity to any network **/
- CONNECTED,
- /**
- * This state is returned if there is no connectivity to any network. This is set
- * to true under two circumstances:
- * <ul>
- * <li>When connectivity is lost to one network, and there is no other available
- * network to attempt to switch to.</li>
- * <li>When connectivity is lost to one network, and the attempt to switch to
- * another network fails.</li>
- */
- NOT_CONNECTED
- }
-
- /**
- * Create a new NetworkConnectivityListener.
- */
- public NetworkConnectivityListener() {
- mState = State.UNKNOWN;
- mReceiver = new ConnectivityBroadcastReceiver();
- }
-
- /**
- * This method starts listening for network connectivity state changes.
- * @param context
- */
- public synchronized void startListening(Context context) {
- if (!mListening) {
- mContext = context;
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- context.registerReceiver(mReceiver, filter);
- mListening = true;
- }
- }
-
- /**
- * This method stops this class from listening for network changes.
- */
- public synchronized void stopListening() {
- if (mListening) {
- mContext.unregisterReceiver(mReceiver);
- mContext = null;
- mNetworkInfo = null;
- mOtherNetworkInfo = null;
- mIsFailover = false;
- mReason = null;
- mListening = false;
- }
- }
-
- /**
- * This methods registers a Handler to be called back onto with the specified what code when
- * the network connectivity state changes.
- *
- * @param target The target handler.
- * @param what The what code to be used when posting a message to the handler.
- */
- public void registerHandler(Handler target, int what) {
- mHandlers.put(target, what);
- }
-
- /**
- * This methods unregisters the specified Handler.
- * @param target
- */
- public void unregisterHandler(Handler target) {
- mHandlers.remove(target);
- }
-
- public State getState() {
- return mState;
- }
-
- /**
- * Return the NetworkInfo associated with the most recent connectivity event.
- * @return {@code NetworkInfo} for the network that had the most recent connectivity event.
- */
- public NetworkInfo getNetworkInfo() {
- return mNetworkInfo;
- }
-
- /**
- * If the most recent connectivity event was a DISCONNECT, return
- * any information supplied in the broadcast about an alternate
- * network that might be available. If this returns a non-null
- * value, then another broadcast should follow shortly indicating
- * whether connection to the other network succeeded.
- *
- * @return NetworkInfo
- */
- public NetworkInfo getOtherNetworkInfo() {
- return mOtherNetworkInfo;
- }
-
- /**
- * Returns true if the most recent event was for an attempt to switch over to
- * a new network following loss of connectivity on another network.
- * @return {@code true} if this was a failover attempt, {@code false} otherwise.
- */
- public boolean isFailover() {
- return mIsFailover;
- }
-
- /**
- * An optional reason for the connectivity state change may have been supplied.
- * This returns it.
- * @return the reason for the state change, if available, or {@code null}
- * otherwise.
- */
- public String getReason() {
- return mReason;
- }
-}
diff --git a/core/java/android/net/http/DomainNameChecker.java b/core/java/android/net/http/DomainNameChecker.java
index e4c8009..3e01d2c 100644
--- a/core/java/android/net/http/DomainNameChecker.java
+++ b/core/java/android/net/http/DomainNameChecker.java
@@ -231,7 +231,7 @@ public class DomainNameChecker {
rval = thisDomainTokens[i].equals(thatDomainTokens[i]);
if (!rval) {
// (c) OR we have a special *-match:
- // Z.Y.X matches *.Y.X but does not match *.X
+ // *.Y.X matches Z.Y.X but *.X doesn't match Z.Y.X
rval = (i == 0 && thisDomainTokensNum == thatDomainTokensNum);
if (rval) {
rval = thatDomainTokens[0].equals("*");
@@ -242,10 +242,13 @@ public class DomainNameChecker {
thisDomainTokens[0], thatDomainTokens[0]);
}
}
-
break;
}
}
+ } else {
+ // (e) OR thatHost has a '*.'-prefix of thisHost:
+ // *.Y.X matches Y.X
+ rval = thatDomain.equals("*." + thisDomain);
}
}
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 7d2c698..d28148c 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -82,7 +82,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* <li><code>Result</code>, the type of the result of the background
* computation.</li>
* </ol>
- * <p>Not all types are always used by am asynchronous task. To mark a type as unused,
+ * <p>Not all types are always used by an asynchronous task. To mark a type as unused,
* simply use the type {@link Void}:</p>
* <pre>
* private class MyTask extends AsyncTask&lt;Void, Void, Void&gt; { ... }
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 6212b17..eed2af7 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -18,6 +18,8 @@ package android.os;
import java.io.File;
+import android.os.IMountService;
+
/**
* Provides access to environment variables.
*/
@@ -28,6 +30,8 @@ public class Environment {
private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
+ private static IMountService mMntSvc = null;
+
/**
* Gets the Android root directory.
*/
@@ -167,9 +171,19 @@ public class Environment {
/**
* Gets the current state of the external storage device.
+ * Note: This call should be deprecated as it doesn't support
+ * multiple volumes.
*/
public static String getExternalStorageState() {
- return SystemProperties.get("EXTERNAL_STORAGE_STATE", MEDIA_REMOVED);
+ try {
+ if (mMntSvc == null) {
+ mMntSvc = IMountService.Stub.asInterface(ServiceManager
+ .getService("mount"));
+ }
+ return mMntSvc.getVolumeState(getExternalStorageDirectory().toString());
+ } catch (android.os.RemoteException rex) {
+ return Environment.MEDIA_REMOVED;
+ }
}
static File getDirectory(String variableName, String defaultPath) {
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index 38d252e..3457815 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -103,9 +103,7 @@ public abstract class FileObserver {
try {
observer.onEvent(mask, path);
} catch (Throwable throwable) {
- Log.e(LOG_TAG, "Unhandled throwable " + throwable.toString() +
- " (returned by observer " + observer + ")", throwable);
- RuntimeInit.crash("FileObserver", throwable);
+ Log.wtf(LOG_TAG, "Unhandled exception in FileObserver " + observer, throwable);
}
}
}
diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl
index 96d44b6..1ea7200 100644
--- a/core/java/android/os/IMountService.aidl
+++ b/core/java/android/os/IMountService.aidl
@@ -75,4 +75,44 @@ interface IMountService
* when a UMS host is detected.
*/
void setAutoStartUms(boolean value);
+
+ /**
+ * Gets the state of an volume via it's mountpoint.
+ */
+ String getVolumeState(String mountPoint);
+
+ /*
+ * Creates a secure cache with the specified parameters.
+ * On success, the filesystem cache-path is returned.
+ */
+ String createSecureCache(String id, int sizeMb, String fstype, String key, int ownerUid);
+
+ /*
+ * Finalize a cache which has just been created and populated.
+ * After finalization, the cache is immutable.
+ */
+ void finalizeSecureCache(String id);
+
+ /*
+ * Destroy a secure cache, and free up all resources associated with it.
+ * NOTE: Ensure all references are released prior to deleting.
+ */
+ void destroySecureCache(String id);
+
+ /*
+ * Mount a secure cache with the specified key and owner UID.
+ * On success, the filesystem cache-path is returned.
+ */
+ String mountSecureCache(String id, String key, int ownerUid);
+
+ /*
+ * Returns the filesystem path of a mounted secure cache.
+ */
+ String getSecureCachePath(String id);
+
+ /**
+ * Gets an Array of currently known secure cache IDs
+ */
+ String[] getSecureCacheList();
+
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 0afc537..23762ca 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -31,6 +31,7 @@ interface IPowerManager
void preventScreenOn(boolean prevent);
boolean isScreenOn();
void reboot(String reason);
+ void crash(String message);
// sets the brightness of the backlights (screen, keyboard, button) 0-255
void setBacklightBrightness(int brightness);
diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java
index 03542dd..9742b05 100644
--- a/core/java/android/os/MemoryFile.java
+++ b/core/java/android/os/MemoryFile.java
@@ -52,7 +52,7 @@ public class MemoryFile
private static native void native_write(FileDescriptor fd, int address, byte[] buffer,
int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
private static native void native_pin(FileDescriptor fd, boolean pin) throws IOException;
- private static native int native_get_mapped_size(FileDescriptor fd) throws IOException;
+ private static native int native_get_size(FileDescriptor fd) throws IOException;
private FileDescriptor mFD; // ashmem file descriptor
private int mAddress; // address of ashmem memory
@@ -300,20 +300,19 @@ public class MemoryFile
* @hide
*/
public static boolean isMemoryFile(FileDescriptor fd) throws IOException {
- return (native_get_mapped_size(fd) >= 0);
+ return (native_get_size(fd) >= 0);
}
/**
- * Returns the size of the memory file, rounded up to a page boundary, that
- * the file descriptor refers to, or -1 if the file descriptor does not
- * refer to a memory file.
+ * Returns the size of the memory file that the file descriptor refers to,
+ * or -1 if the file descriptor does not refer to a memory file.
*
* @throws IOException If <code>fd</code> is not a valid file descriptor.
*
* @hide
*/
- public static int getMappedSize(FileDescriptor fd) throws IOException {
- return native_get_mapped_size(fd);
+ public static int getSize(FileDescriptor fd) throws IOException {
+ return native_get_size(fd);
}
/**
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index caf0923..bc653d6 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -115,9 +115,7 @@ public class MessageQueue {
didIdle = true;
keep = ((IdleHandler)idler).queueIdle();
} catch (Throwable t) {
- Log.e("MessageQueue",
- "IdleHandler threw exception", t);
- RuntimeInit.crash("MessageQueue", t);
+ Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 293dabc..e4eaf45 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -326,12 +326,11 @@ public class PowerManager
{
synchronized (mToken) {
if (mHeld) {
+ Log.wtf(TAG, "WakeLock finalized while still held: " + mTag);
try {
mService.releaseWakeLock(mToken, 0);
} catch (RemoteException e) {
}
- RuntimeInit.crash(TAG, new Exception(
- "WakeLock finalized while still held: "+mTag));
}
}
}
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
new file mode 100644
index 0000000..3dd3918
--- /dev/null
+++ b/core/java/android/os/RecoverySystem.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2010 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.os;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import android.content.Context;
+import android.util.Log;
+
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.pkcs7.ContentInfo;
+import org.apache.harmony.security.pkcs7.SignedData;
+import org.apache.harmony.security.pkcs7.SignerInfo;
+import org.apache.harmony.security.provider.cert.X509CertImpl;
+
+/**
+ * RecoverySystem contains methods for interacting with the Android
+ * recovery system (the separate partition that can be used to install
+ * system updates, wipe user data, etc.)
+ */
+public class RecoverySystem {
+ private static final String TAG = "RecoverySystem";
+
+ /**
+ * Default location of zip file containing public keys (X509
+ * certs) authorized to sign OTA updates.
+ */
+ private static final File DEFAULT_KEYSTORE =
+ new File("/system/etc/security/otacerts.zip");
+
+ /** Send progress to listeners no more often than this (in ms). */
+ private static final long PUBLISH_PROGRESS_INTERVAL_MS = 500;
+
+ /** Used to communicate with recovery. See bootable/recovery/recovery.c. */
+ private static File RECOVERY_DIR = new File("/cache/recovery");
+ private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
+ private static File LOG_FILE = new File(RECOVERY_DIR, "log");
+
+ // Length limits for reading files.
+ private static int LOG_FILE_MAX_LENGTH = 8 * 1024;
+
+ /**
+ * Interface definition for a callback to be invoked regularly as
+ * verification proceeds.
+ */
+ public interface ProgressListener {
+ /**
+ * Called periodically as the verification progresses.
+ *
+ * @param progress the approximate percentage of the
+ * verification that has been completed, ranging from 0
+ * to 100 (inclusive).
+ */
+ public void onProgress(int progress);
+ }
+
+ /** @return the set of certs that can be used to sign an OTA package. */
+ private static HashSet<Certificate> getTrustedCerts(File keystore)
+ throws IOException, GeneralSecurityException {
+ HashSet<Certificate> trusted = new HashSet<Certificate>();
+ if (keystore == null) {
+ keystore = DEFAULT_KEYSTORE;
+ }
+ ZipFile zip = new ZipFile(keystore);
+ try {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ Enumeration<? extends ZipEntry> entries = zip.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ trusted.add(cf.generateCertificate(zip.getInputStream(entry)));
+ }
+ } finally {
+ zip.close();
+ }
+ return trusted;
+ }
+
+ /**
+ * Verify the cryptographic signature of a system update package
+ * before installing it. Note that the package is also verified
+ * separately by the installer once the device is rebooted into
+ * the recovery system. This function will return only if the
+ * package was successfully verified; otherwise it will throw an
+ * exception.
+ *
+ * Verification of a package can take significant time, so this
+ * function should not be called from a UI thread.
+ *
+ * @param packageFile the package to be verified
+ * @param listener an object to receive periodic progress
+ * updates as verification proceeds. May be null.
+ * @param deviceCertsZipFile the zip file of certificates whose
+ * public keys we will accept. Verification succeeds if the
+ * package is signed by the private key corresponding to any
+ * public key in this file. May be null to use the system default
+ * file (currently "/system/etc/security/otacerts.zip").
+ *
+ * @throws IOException if there were any errors reading the
+ * package or certs files.
+ * @throws GeneralSecurityException if verification failed
+ */
+ public static void verifyPackage(File packageFile,
+ ProgressListener listener,
+ File deviceCertsZipFile)
+ throws IOException, GeneralSecurityException {
+ long fileLen = packageFile.length();
+
+ RandomAccessFile raf = new RandomAccessFile(packageFile, "r");
+ try {
+ int lastPercent = 0;
+ long lastPublishTime = System.currentTimeMillis();
+ if (listener != null) {
+ listener.onProgress(lastPercent);
+ }
+
+ raf.seek(fileLen - 6);
+ byte[] footer = new byte[6];
+ raf.readFully(footer);
+
+ if (footer[2] != (byte)0xff || footer[3] != (byte)0xff) {
+ throw new SignatureException("no signature in file (no footer)");
+ }
+
+ int commentSize = (footer[4] & 0xff) | ((footer[5] & 0xff) << 8);
+ int signatureStart = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8);
+ Log.v(TAG, String.format("comment size %d; signature start %d",
+ commentSize, signatureStart));
+
+ byte[] eocd = new byte[commentSize + 22];
+ raf.seek(fileLen - (commentSize + 22));
+ raf.readFully(eocd);
+
+ // Check that we have found the start of the
+ // end-of-central-directory record.
+ if (eocd[0] != (byte)0x50 || eocd[1] != (byte)0x4b ||
+ eocd[2] != (byte)0x05 || eocd[3] != (byte)0x06) {
+ throw new SignatureException("no signature in file (bad footer)");
+ }
+
+ for (int i = 4; i < eocd.length-3; ++i) {
+ if (eocd[i ] == (byte)0x50 && eocd[i+1] == (byte)0x4b &&
+ eocd[i+2] == (byte)0x05 && eocd[i+3] == (byte)0x06) {
+ throw new SignatureException("EOCD marker found after start of EOCD");
+ }
+ }
+
+ // The following code is largely copied from
+ // JarUtils.verifySignature(). We could just *call* that
+ // method here if that function didn't read the entire
+ // input (ie, the whole OTA package) into memory just to
+ // compute its message digest.
+
+ BerInputStream bis = new BerInputStream(
+ new ByteArrayInputStream(eocd, commentSize+22-signatureStart, signatureStart));
+ ContentInfo info = (ContentInfo)ContentInfo.ASN1.decode(bis);
+ SignedData signedData = info.getSignedData();
+ if (signedData == null) {
+ throw new IOException("signedData is null");
+ }
+ Collection encCerts = signedData.getCertificates();
+ if (encCerts.isEmpty()) {
+ throw new IOException("encCerts is empty");
+ }
+ // Take the first certificate from the signature (packages
+ // should contain only one).
+ Iterator it = encCerts.iterator();
+ X509Certificate cert = null;
+ if (it.hasNext()) {
+ cert = new X509CertImpl((org.apache.harmony.security.x509.Certificate)it.next());
+ } else {
+ throw new SignatureException("signature contains no certificates");
+ }
+
+ List sigInfos = signedData.getSignerInfos();
+ SignerInfo sigInfo;
+ if (!sigInfos.isEmpty()) {
+ sigInfo = (SignerInfo)sigInfos.get(0);
+ } else {
+ throw new IOException("no signer infos!");
+ }
+
+ // Check that the public key of the certificate contained
+ // in the package equals one of our trusted public keys.
+
+ HashSet<Certificate> trusted = getTrustedCerts(
+ deviceCertsZipFile == null ? DEFAULT_KEYSTORE : deviceCertsZipFile);
+
+ PublicKey signatureKey = cert.getPublicKey();
+ boolean verified = false;
+ for (Certificate c : trusted) {
+ if (c.getPublicKey().equals(signatureKey)) {
+ verified = true;
+ break;
+ }
+ }
+ if (!verified) {
+ throw new SignatureException("signature doesn't match any trusted key");
+ }
+
+ // The signature cert matches a trusted key. Now verify that
+ // the digest in the cert matches the actual file data.
+
+ // The verifier in recovery *only* handles SHA1withRSA
+ // signatures. SignApk.java always uses SHA1withRSA, no
+ // matter what the cert says to use. Ignore
+ // cert.getSigAlgName(), and instead use whatever
+ // algorithm is used by the signature (which should be
+ // SHA1withRSA).
+
+ String da = sigInfo.getdigestAlgorithm();
+ String dea = sigInfo.getDigestEncryptionAlgorithm();
+ String alg = null;
+ if (da == null || dea == null) {
+ // fall back to the cert algorithm if the sig one
+ // doesn't look right.
+ alg = cert.getSigAlgName();
+ } else {
+ alg = da + "with" + dea;
+ }
+ Signature sig = Signature.getInstance(alg);
+ sig.initVerify(cert);
+
+ // The signature covers all of the OTA package except the
+ // archive comment and its 2-byte length.
+ long toRead = fileLen - commentSize - 2;
+ long soFar = 0;
+ raf.seek(0);
+ byte[] buffer = new byte[4096];
+ while (soFar < toRead) {
+ int size = buffer.length;
+ if (soFar + size > toRead) {
+ size = (int)(toRead - soFar);
+ }
+ int read = raf.read(buffer, 0, size);
+ sig.update(buffer, 0, read);
+ soFar += read;
+
+ if (listener != null) {
+ long now = System.currentTimeMillis();
+ int p = (int)(soFar * 100 / toRead);
+ if (p > lastPercent &&
+ now - lastPublishTime > PUBLISH_PROGRESS_INTERVAL_MS) {
+ lastPercent = p;
+ lastPublishTime = now;
+ listener.onProgress(lastPercent);
+ }
+ }
+ }
+ if (listener != null) {
+ listener.onProgress(100);
+ }
+
+ if (!sig.verify(sigInfo.getEncryptedDigest())) {
+ throw new SignatureException("signature digest verification failed");
+ }
+ } finally {
+ raf.close();
+ }
+ }
+
+ /**
+ * Reboots the device in order to install the given update
+ * package.
+ * Requires the {@link android.Manifest.permission#REBOOT}
+ * and {@link android.Manifest.permission#ACCESS_CACHE_FILESYSTEM}
+ * permissions.
+ *
+ * @param context the Context to use
+ * @param packageFile the update package to install. Currently
+ * must be on the /cache or /data partitions.
+ *
+ * @throws IOException if writing the recovery command file
+ * fails, or if the reboot itself fails.
+ */
+ public static void installPackage(Context context, File packageFile)
+ throws IOException {
+ String filename = packageFile.getCanonicalPath();
+
+ if (filename.startsWith("/cache/")) {
+ filename = "CACHE:" + filename.substring(7);
+ } else if (filename.startsWith("/data/")) {
+ filename = "DATA:" + filename.substring(6);
+ } else {
+ throw new IllegalArgumentException(
+ "Must start with /cache or /data: " + filename);
+ }
+ Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
+ String arg = "--update_package=" + filename;
+ bootCommand(context, arg);
+ }
+
+ /**
+ * Reboots the device and wipes the user data partition. This is
+ * sometimes called a "factory reset", which is something of a
+ * misnomer because the system partition is not restored to its
+ * factory state.
+ * Requires the {@link android.Manifest.permission#REBOOT}
+ * and {@link android.Manifest.permission#ACCESS_CACHE_FILESYSTEM}
+ * permissions.
+ *
+ * @param context the Context to use
+ *
+ * @throws IOException if writing the recovery command file
+ * fails, or if the reboot itself fails.
+ */
+ public static void rebootWipeUserData(Context context)
+ throws IOException {
+ bootCommand(context, "--wipe_data");
+ }
+
+ /**
+ * Reboot into the recovery system to wipe the /data partition and toggle
+ * Encrypted File Systems on/off.
+ * @param extras to add to the RECOVERY_COMPLETED intent after rebooting.
+ * @throws IOException if something goes wrong.
+ *
+ * @hide
+ */
+ public static void rebootToggleEFS(Context context, boolean efsEnabled)
+ throws IOException {
+ if (efsEnabled) {
+ bootCommand(context, "--set_encrypted_filesystem=on");
+ } else {
+ bootCommand(context, "--set_encrypted_filesystem=off");
+ }
+ }
+
+ /**
+ * Reboot into the recovery system with the supplied argument.
+ * @param arg to pass to the recovery utility.
+ * @throws IOException if something goes wrong.
+ */
+ private static void bootCommand(Context context, String arg) throws IOException {
+ RECOVERY_DIR.mkdirs(); // In case we need it
+ COMMAND_FILE.delete(); // In case it's not writable
+ LOG_FILE.delete();
+
+ FileWriter command = new FileWriter(COMMAND_FILE);
+ try {
+ command.write(arg);
+ command.write("\n");
+ } finally {
+ command.close();
+ }
+
+ // Having written the command file, go ahead and reboot
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ pm.reboot("recovery");
+
+ throw new IOException("Reboot failed (no permissions?)");
+ }
+
+ /**
+ * Called after booting to process and remove recovery-related files.
+ * @return the log file from recovery, or null if none was found.
+ *
+ * @hide
+ */
+ public static String handleAftermath() {
+ // Record the tail of the LOG_FILE
+ String log = null;
+ try {
+ log = FileUtils.readTextFile(LOG_FILE, -LOG_FILE_MAX_LENGTH, "...\n");
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "No recovery log file");
+ } catch (IOException e) {
+ Log.e(TAG, "Error reading recovery log", e);
+ }
+
+ // Delete everything in RECOVERY_DIR
+ String[] names = RECOVERY_DIR.list();
+ for (int i = 0; names != null && i < names.length; i++) {
+ File f = new File(RECOVERY_DIR, names[i]);
+ if (!f.delete()) {
+ Log.e(TAG, "Can't delete: " + f);
+ } else {
+ Log.i(TAG, "Deleted: " + f);
+ }
+ }
+
+ return log;
+ }
+
+ private void RecoverySystem() { } // Do not instantiate
+}
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index 4eaea6a..389c9f4 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -54,6 +54,7 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
+import java.lang.reflect.Method;
import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -197,7 +198,7 @@ public class VCardComposer {
if (mIsDoCoMo) {
try {
// Create one empty entry.
- mWriter.write(createOneEntryInternal("-1"));
+ mWriter.write(createOneEntryInternal("-1", null));
} catch (IOException e) {
Log.e(LOG_TAG,
"IOException occurred during exportOneContactData: "
@@ -428,6 +429,14 @@ public class VCardComposer {
}
public boolean createOneEntry() {
+ return createOneEntry(null);
+ }
+
+ /**
+ * @param getEntityIteratorMethod For Dependency Injection.
+ * @hide just for testing.
+ */
+ public boolean createOneEntry(Method getEntityIteratorMethod) {
if (mCursor == null || mCursor.isAfterLast()) {
mErrorReason = FAILURE_REASON_NOT_INITIALIZED;
return false;
@@ -439,7 +448,8 @@ public class VCardComposer {
vcard = createOneCallLogEntryInternal();
} else {
if (mIdColumn >= 0) {
- vcard = createOneEntryInternal(mCursor.getString(mIdColumn));
+ vcard = createOneEntryInternal(mCursor.getString(mIdColumn),
+ getEntityIteratorMethod);
} else {
Log.e(LOG_TAG, "Incorrect mIdColumn: " + mIdColumn);
return true;
@@ -475,7 +485,8 @@ public class VCardComposer {
return true;
}
- private String createOneEntryInternal(final String contactId) {
+ private String createOneEntryInternal(final String contactId,
+ Method getEntityIteratorMethod) {
final Map<String, List<ContentValues>> contentValuesListMap =
new HashMap<String, List<ContentValues>>();
// The resolver may return the entity iterator with no data. It is possiible.
@@ -484,13 +495,34 @@ public class VCardComposer {
boolean dataExists = false;
EntityIterator entityIterator = null;
try {
- final Uri uri = RawContacts.CONTENT_URI.buildUpon()
- .appendEncodedPath(contactId)
- .appendEncodedPath(RawContacts.Entity.CONTENT_DIRECTORY)
- .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
- .build();
- entityIterator = RawContacts.newEntityIterator(mContentResolver.query(
- uri, null, null, null, null));
+
+ if (getEntityIteratorMethod != null) {
+ try {
+ final Uri uri = RawContacts.CONTENT_URI.buildUpon()
+ .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
+ .build();
+ final String selection = Data.CONTACT_ID + "=?";
+ final String[] selectionArgs = new String[] {contactId};
+ entityIterator = (EntityIterator)getEntityIteratorMethod.invoke(null,
+ mContentResolver, uri, selection, selectionArgs, null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ final Uri uri = RawContacts.CONTENT_URI.buildUpon()
+ .appendEncodedPath(contactId)
+ .appendEncodedPath(RawContacts.Entity.CONTENT_DIRECTORY)
+ .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
+ .build();
+ entityIterator = RawContacts.newEntityIterator(mContentResolver.query(
+ uri, null, null, null, null));
+ }
+
+ if (entityIterator == null) {
+ Log.e(LOG_TAG, "EntityIterator is null");
+ return "";
+ }
+
dataExists = entityIterator.hasNext();
while (entityIterator.hasNext()) {
Entity entity = entityIterator.next();
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index b74564a..a94b3b4 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -1059,11 +1059,23 @@ public final class Calendar {
* <P>Type: INTEGER</P>
*/
public static final String MAX_BUSYBITS = "maxBusyBits";
+
+ /**
+ * The minimum Julian day in the EventDays table.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String MIN_EVENTDAYS = "minEventDays";
+
+ /**
+ * The maximum Julian day in the EventDays table.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String MAX_EVENTDAYS = "maxEventDays";
}
public static final class CalendarMetaData implements CalendarMetaDataColumns {
}
-
+ /*busybits*/
public interface BusyBitsColumns {
/**
* The Julian day number.
@@ -1088,6 +1100,7 @@ public final class Calendar {
public static final String ALL_DAY_COUNT = "allDayCount";
}
+ /*busybits*/
public static final class BusyBits implements BusyBitsColumns {
public static final Uri CONTENT_URI = Uri.parse("content://calendar/busybits/when");
@@ -1102,6 +1115,47 @@ public final class Calendar {
/**
* Retrieves the busy bits for the Julian days starting at "startDay"
* for "numDays".
+ * This is being phased out so has been changed to an empty method so
+ * that it doesn't reference anything that needs to be cleaned up else-
+ * where.
+ *
+ * @param cr the ContentResolver
+ * @param startDay the first Julian day in the range
+ * @param numDays the number of days to load (must be at least 1)
+ * @return a database cursor
+ */
+ public static final Cursor query(ContentResolver cr, int startDay, int numDays) {
+// if (numDays < 1) {
+// return null;
+// }
+// int endDay = startDay + numDays - 1;
+// Uri.Builder builder = CONTENT_URI.buildUpon();
+// ContentUris.appendId(builder, startDay);
+// ContentUris.appendId(builder, endDay);
+// return cr.query(builder.build(), PROJECTION, null /* selection */,
+// null /* selection args */, DAY);
+ return null;
+ }
+ }
+
+ public interface EventDaysColumns {
+ /**
+ * The Julian starting day number.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String STARTDAY = "startDay";
+
+ }
+
+ public static final class EventDays implements EventDaysColumns {
+ public static final Uri CONTENT_URI = Uri.parse("content://calendar/instances/groupbyday");
+
+ public static final String[] PROJECTION = { STARTDAY };
+ public static final String SELECTION = "selected==1";
+
+ /**
+ * Retrieves the days with events for the Julian days starting at "startDay"
+ * for "numDays".
*
* @param cr the ContentResolver
* @param startDay the first Julian day in the range
@@ -1116,8 +1170,8 @@ public final class Calendar {
Uri.Builder builder = CONTENT_URI.buildUpon();
ContentUris.appendId(builder, startDay);
ContentUris.appendId(builder, endDay);
- return cr.query(builder.build(), PROJECTION, null /* selection */,
- null /* selection args */, DAY);
+ return cr.query(builder.build(), PROJECTION, SELECTION,
+ null /* selection args */, STARTDAY);
}
}
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 1a38166..a29ecb5 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -1334,8 +1334,26 @@ public class Contacts {
}
/**
+ * TODO find a place to put the canonical version of these.
+ */
+ interface ProviderNames {
+ //
+ //NOTE: update Contacts.java with new providers when they're added.
+ //
+ String YAHOO = "Yahoo";
+ String GTALK = "GTalk";
+ String MSN = "MSN";
+ String ICQ = "ICQ";
+ String AIM = "AIM";
+ String XMPP = "XMPP";
+ String JABBER = "JABBER";
+ String SKYPE = "SKYPE";
+ String QQ = "QQ";
+ }
+
+ /**
* This looks up the provider name defined in
- * {@link android.provider.Im.ProviderNames} from the predefined IM protocol id.
+ * from the predefined IM protocol id.
* This is used for interacting with the IM application.
*
* @param protocol the protocol ID
@@ -1348,21 +1366,21 @@ public class Contacts {
public static String lookupProviderNameFromId(int protocol) {
switch (protocol) {
case PROTOCOL_GOOGLE_TALK:
- return Im.ProviderNames.GTALK;
+ return ProviderNames.GTALK;
case PROTOCOL_AIM:
- return Im.ProviderNames.AIM;
+ return ProviderNames.AIM;
case PROTOCOL_MSN:
- return Im.ProviderNames.MSN;
+ return ProviderNames.MSN;
case PROTOCOL_YAHOO:
- return Im.ProviderNames.YAHOO;
+ return ProviderNames.YAHOO;
case PROTOCOL_ICQ:
- return Im.ProviderNames.ICQ;
+ return ProviderNames.ICQ;
case PROTOCOL_JABBER:
- return Im.ProviderNames.JABBER;
+ return ProviderNames.JABBER;
case PROTOCOL_SKYPE:
- return Im.ProviderNames.SKYPE;
+ return ProviderNames.SKYPE;
case PROTOCOL_QQ:
- return Im.ProviderNames.QQ;
+ return ProviderNames.QQ;
}
return null;
}
@@ -1532,7 +1550,35 @@ public class Contacts {
* @deprecated see {@link android.provider.ContactsContract}
*/
@Deprecated
- public interface PresenceColumns extends Im.CommonPresenceColumns {
+ public interface PresenceColumns {
+ /**
+ * The priority, an integer, used by XMPP presence
+ * <P>Type: INTEGER</P>
+ */
+ String PRIORITY = "priority";
+
+ /**
+ * The server defined status.
+ * <P>Type: INTEGER (one of the values below)</P>
+ */
+ String PRESENCE_STATUS = ContactsContract.StatusUpdates.PRESENCE;
+
+ /**
+ * Presence Status definition
+ */
+ int OFFLINE = ContactsContract.StatusUpdates.OFFLINE;
+ int INVISIBLE = ContactsContract.StatusUpdates.INVISIBLE;
+ int AWAY = ContactsContract.StatusUpdates.AWAY;
+ int IDLE = ContactsContract.StatusUpdates.IDLE;
+ int DO_NOT_DISTURB = ContactsContract.StatusUpdates.DO_NOT_DISTURB;
+ int AVAILABLE = ContactsContract.StatusUpdates.AVAILABLE;
+
+ /**
+ * The user defined status line.
+ * <P>Type: TEXT</P>
+ */
+ String PRESENCE_CUSTOM_STATUS = ContactsContract.StatusUpdates.STATUS;
+
/**
* The IM service the presence is coming from. Formatted using either
* {@link Contacts.ContactMethods#encodePredefinedImProtocol} or
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index e98d8ee..ac8bf91 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -35,6 +35,7 @@ import android.graphics.Rect;
import android.net.Uri;
import android.os.RemoteException;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.Pair;
import android.view.View;
@@ -294,7 +295,7 @@ public final class ContactsContract {
* The display name for the contact.
* <P>Type: TEXT</P>
*/
- public static final String DISPLAY_NAME = "display_name";
+ public static final String DISPLAY_NAME = ContactNameColumns.DISPLAY_NAME_PRIMARY;
/**
* Reference to the row in the RawContacts table holding the contact name.
@@ -456,13 +457,13 @@ public final class ContactsContract {
* The default text shown as the contact's display name. It is based on
* available data, see {@link #DISPLAY_NAME_SOURCE}.
*/
- public static final String DISPLAY_NAME = "display_name";
+ public static final String DISPLAY_NAME_PRIMARY = "display_name";
/**
* Alternative representation of the display name. If display name is
* based on the structured name and the structured name follows
* the Western full name style, then this field contains the "family name first"
- * version of the full name. Otherwise, it is the same as {@link #DISPLAY_NAME}.
+ * version of the full name. Otherwise, it is the same as DISPLAY_NAME_PRIMARY.
*/
public static final String DISPLAY_NAME_ALTERNATIVE = "display_name_alt";
@@ -483,7 +484,7 @@ public final class ContactsContract {
* the sort key is the name's Pinyin spelling; for Japanese names
* it is the Hiragana version of the phonetic name.
*/
- public static final String SORT_KEY = "sort_key";
+ public static final String SORT_KEY_PRIMARY = "sort_key";
/**
* Sort key based on the alternative representation of the full name,
@@ -562,7 +563,7 @@ public final class ContactsContract {
* </tr>
* <tr>
* <td>String</td>
- * <td>{@link #DISPLAY_NAME}</td>
+ * <td>DISPLAY_NAME_PRIMARY</td>
* <td>read-only</td>
* <td>The display name for the contact. It is the display name
* contributed by the raw contact referred to by the NAME_RAW_CONTACT_ID
@@ -692,7 +693,7 @@ public final class ContactsContract {
* </table>
*/
public static class Contacts implements BaseColumns, ContactsColumns,
- ContactOptionsColumns, ContactStatusColumns {
+ ContactOptionsColumns, ContactNameColumns, ContactStatusColumns {
/**
* This utility class cannot be instantiated
*/
@@ -1519,6 +1520,7 @@ public final class ContactsContract {
super(cursor);
}
+ @Override
public android.content.Entity getEntityAndIncrementCursor(Cursor cursor)
throws RemoteException {
final int columnRawContactId = cursor.getColumnIndexOrThrow(RawContacts._ID);
@@ -1601,18 +1603,39 @@ public final class ContactsContract {
* @see StatusUpdates
* @see ContactsContract.Data
*/
- protected interface StatusColumns extends Im.CommonPresenceColumns {
+ protected interface StatusColumns {
/**
* Contact's latest presence level.
* <P>Type: INTEGER (one of the values below)</P>
*/
- public static final String PRESENCE = PRESENCE_STATUS;
+ public static final String PRESENCE = "mode";
+
+ /**
+ * @deprecated use {@link #PRESENCE}
+ */
+ @Deprecated
+ public static final String PRESENCE_STATUS = PRESENCE;
+
+ /*
+ * Presence Status definition
+ */
+ int OFFLINE = 0;
+ int INVISIBLE = 1;
+ int AWAY = 2;
+ int IDLE = 3;
+ int DO_NOT_DISTURB = 4;
+ int AVAILABLE = 5;
/**
* Contact latest status update.
* <p>Type: TEXT</p>
*/
- public static final String STATUS = PRESENCE_CUSTOM_STATUS;
+ public static final String STATUS = "status";
+
+ /**
+ * @deprecated use {@link #STATUS}
+ */
+ public static final String PRESENCE_CUSTOM_STATUS = STATUS;
/**
* The absolute time in milliseconds when the latest status was inserted/updated.
@@ -1736,8 +1759,8 @@ public final class ContactsContract {
* @see ContactsContract.Data
*/
protected interface DataColumnsWithJoins extends BaseColumns, DataColumns, StatusColumns,
- RawContactsColumns, ContactsColumns, ContactOptionsColumns, ContactStatusColumns {
-
+ RawContactsColumns, ContactsColumns, ContactNameColumns, ContactOptionsColumns,
+ ContactStatusColumns {
}
/**
@@ -3018,7 +3041,7 @@ public final class ContactsContract {
/**
* The alphabet used for capturing the phonetic name.
- * See {@link ContactsContract.PhoneticNameStyle}.
+ * See ContactsContract.PhoneticNameStyle.
* @hide
*/
public static final String PHONETIC_NAME_STYLE = DATA11;
@@ -3901,6 +3924,12 @@ public final class ContactsContract {
* <td>{@link #DATA9}</td>
* <td></td>
* </tr>
+ * <tr>
+ * <td>String</td>
+ * <td>PHONETIC_NAME_STYLE</td>
+ * <td>{@link #DATA10}</td>
+ * <td></td>
+ * </tr>
* </table>
*/
public static final class Organization implements DataColumnsWithJoins, CommonColumns {
@@ -3958,6 +3987,13 @@ public final class ContactsContract {
public static final String OFFICE_LOCATION = DATA9;
/**
+ * The alphabet used for capturing the phonetic name.
+ * See {@link ContactsContract.PhoneticNameStyle}.
+ * @hide
+ */
+ public static final String PHONETIC_NAME_STYLE = DATA10;
+
+ /**
* Return the string resource that best describes the given
* {@link #TYPE}. Will always return a valid resource.
*/
@@ -4578,6 +4614,7 @@ public final class ContactsContract {
super(cursor);
}
+ @Override
public Entity getEntityAndIncrementCursor(Cursor cursor) throws RemoteException {
// we expect the cursor is already at the row we need to read from
final ContentValues values = new ContentValues();
@@ -4860,8 +4897,10 @@ public final class ContactsContract {
/**
* Extra used to specify pivot dialog location in screen coordinates.
+ * @deprecated Use {@link Intent#setSourceBounds(Rect)} instead.
* @hide
*/
+ @Deprecated
public static final String EXTRA_TARGET_RECT = "target_rect";
/**
@@ -4921,15 +4960,17 @@ public final class ContactsContract {
*/
public static void showQuickContact(Context context, View target, Uri lookupUri, int mode,
String[] excludeMimes) {
- // Find location and bounds of target view
- final int[] location = new int[2];
- target.getLocationOnScreen(location);
+ // Find location and bounds of target view, adjusting based on the
+ // assumed local density.
+ final float appScale = context.getResources().getCompatibilityInfo().applicationScale;
+ final int[] pos = new int[2];
+ target.getLocationOnScreen(pos);
final Rect rect = new Rect();
- rect.left = location[0];
- rect.top = location[1];
- rect.right = rect.left + target.getWidth();
- rect.bottom = rect.top + target.getHeight();
+ rect.left = (int) (pos[0] * appScale + 0.5f);
+ rect.top = (int) (pos[1] * appScale + 0.5f);
+ rect.right = (int) ((pos[0] + target.getWidth()) * appScale + 0.5f);
+ rect.bottom = (int) ((pos[1] + target.getHeight()) * appScale + 0.5f);
// Trigger with obtained rectangle
showQuickContact(context, rect, lookupUri, mode, excludeMimes);
@@ -4946,8 +4987,11 @@ public final class ContactsContract {
* @param target Specific {@link Rect} that this dialog should be
* centered around, in screen coordinates. In particular, if
* the dialog has a "callout" arrow, it will be pointed and
- * centered around this {@link Rect}.
- * @param lookupUri A {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
+ * centered around this {@link Rect}. If you are running at a
+ * non-native density, you need to manually adjust using
+ * {@link DisplayMetrics#density} before calling.
+ * @param lookupUri A
+ * {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
* {@link Uri} that describes a specific contact to feature
* in this dialog.
* @param mode Any of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or
@@ -4966,7 +5010,7 @@ public final class ContactsContract {
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
intent.setData(lookupUri);
- intent.putExtra(EXTRA_TARGET_RECT, target);
+ intent.setSourceBounds(target);
intent.putExtra(EXTRA_MODE, mode);
intent.putExtra(EXTRA_EXCLUDE_MIMES, excludeMimes);
context.startActivity(intent);
diff --git a/core/java/android/provider/Im.java b/core/java/android/provider/Im.java
deleted file mode 100644
index ff52199..0000000
--- a/core/java/android/provider/Im.java
+++ /dev/null
@@ -1,2358 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.provider;
-
-import android.content.ContentQueryMap;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Handler;
-
-import java.util.HashMap;
-
-/**
- * The GTalk provider stores all information about roster contacts, chat messages, presence, etc.
- *
- * @hide
- */
-public class Im {
- /**
- * no public constructor since this is a utility class
- */
- private Im() {}
-
- /**
- * The Columns for IM providers
- */
- public interface ProviderColumns {
- /**
- * The name of the IM provider
- * <P>Type: TEXT</P>
- */
- String NAME = "name";
-
- /**
- * The full name of the provider
- * <P>Type: TEXT</P>
- */
- String FULLNAME = "fullname";
-
- /**
- * The category for the provider, used to form intent.
- * <P>Type: TEXT</P>
- */
- String CATEGORY = "category";
-
- /**
- * The url users should visit to create a new account for this provider
- * <P>Type: TEXT</P>
- */
- String SIGNUP_URL = "signup_url";
- }
-
- /**
- * Known names corresponding to the {@link ProviderColumns#NAME} column
- */
- public interface ProviderNames {
- //
- //NOTE: update Contacts.java with new providers when they're added.
- //
- String YAHOO = "Yahoo";
- String GTALK = "GTalk";
- String MSN = "MSN";
- String ICQ = "ICQ";
- String AIM = "AIM";
- String XMPP = "XMPP";
- String JABBER = "JABBER";
- String SKYPE = "SKYPE";
- String QQ = "QQ";
- }
-
- /**
- * This table contains the IM providers
- */
- public static final class Provider implements BaseColumns, ProviderColumns {
- private Provider() {}
-
- public static final long getProviderIdForName(ContentResolver cr, String providerName) {
- String[] selectionArgs = new String[1];
- selectionArgs[0] = providerName;
-
- Cursor cursor = cr.query(CONTENT_URI,
- PROVIDER_PROJECTION,
- NAME+"=?",
- selectionArgs, null);
-
- long retVal = 0;
- try {
- if (cursor.moveToFirst()) {
- retVal = cursor.getLong(cursor.getColumnIndexOrThrow(_ID));
- }
- } finally {
- cursor.close();
- }
-
- return retVal;
- }
-
- public static final String getProviderNameForId(ContentResolver cr, long providerId) {
- Cursor cursor = cr.query(CONTENT_URI,
- PROVIDER_PROJECTION,
- _ID + "=" + providerId,
- null, null);
-
- String retVal = null;
- try {
- if (cursor.moveToFirst()) {
- retVal = cursor.getString(cursor.getColumnIndexOrThrow(NAME));
- }
- } finally {
- cursor.close();
- }
-
- return retVal;
- }
-
- private static final String[] PROVIDER_PROJECTION = new String[] {
- _ID,
- NAME
- };
-
- public static final String ACTIVE_ACCOUNT_ID = "account_id";
- public static final String ACTIVE_ACCOUNT_USERNAME = "account_username";
- public static final String ACTIVE_ACCOUNT_PW = "account_pw";
- public static final String ACTIVE_ACCOUNT_LOCKED = "account_locked";
- public static final String ACTIVE_ACCOUNT_KEEP_SIGNED_IN = "account_keepSignedIn";
- public static final String ACCOUNT_PRESENCE_STATUS = "account_presenceStatus";
- public static final String ACCOUNT_CONNECTION_STATUS = "account_connStatus";
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/providers");
-
- public static final Uri CONTENT_URI_WITH_ACCOUNT =
- Uri.parse("content://com.google.android.providers.talk/providers/account");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * people.
- */
- public static final String CONTENT_TYPE =
- "vnd.android.cursor.dir/gtalk-providers";
-
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/gtalk-providers";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER = "name ASC";
- }
-
- /**
- * The columns for IM accounts. There can be more than one account for each IM provider.
- */
- public interface AccountColumns {
- /**
- * The name of the account
- * <P>Type: TEXT</P>
- */
- String NAME = "name";
-
- /**
- * The IM provider for this account
- * <P>Type: INTEGER</P>
- */
- String PROVIDER = "provider";
-
- /**
- * The username for this account
- * <P>Type: TEXT</P>
- */
- String USERNAME = "username";
-
- /**
- * The password for this account
- * <P>Type: TEXT</P>
- */
- String PASSWORD = "pw";
-
- /**
- * A boolean value indicates if the account is active.
- * <P>Type: INTEGER</P>
- */
- String ACTIVE = "active";
-
- /**
- * A boolean value indicates if the account is locked (not editable)
- * <P>Type: INTEGER</P>
- */
- String LOCKED = "locked";
-
- /**
- * A boolean value to indicate whether this account is kept signed in.
- * <P>Type: INTEGER</P>
- */
- String KEEP_SIGNED_IN = "keep_signed_in";
-
- /**
- * A boolean value indiciating the last login state for this account
- * <P>Type: INTEGER</P>
- */
- String LAST_LOGIN_STATE = "last_login_state";
- }
-
- /**
- * This table contains the IM accounts.
- */
- public static final class Account implements BaseColumns, AccountColumns {
- private Account() {}
-
- public static final long getProviderIdForAccount(ContentResolver cr, long accountId) {
- Cursor cursor = cr.query(CONTENT_URI,
- PROVIDER_PROJECTION,
- _ID + "=" + accountId,
- null /* selection args */,
- null /* sort order */);
-
- long providerId = 0;
-
- try {
- if (cursor.moveToFirst()) {
- providerId = cursor.getLong(PROVIDER_COLUMN);
- }
- } finally {
- cursor.close();
- }
-
- return providerId;
- }
-
- private static final String[] PROVIDER_PROJECTION = new String[] { PROVIDER };
- private static final int PROVIDER_COLUMN = 0;
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/accounts");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * account.
- */
- public static final String CONTENT_TYPE =
- "vnd.android.cursor.dir/gtalk-accounts";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
- * account.
- */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/gtalk-accounts";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER = "name ASC";
-
- }
-
- /**
- * Connection status
- */
- public interface ConnectionStatus {
- /**
- * The connection is offline, not logged in.
- */
- int OFFLINE = 0;
-
- /**
- * The connection is attempting to connect.
- */
- int CONNECTING = 1;
-
- /**
- * The connection is suspended due to network not available.
- */
- int SUSPENDED = 2;
-
- /**
- * The connection is logged in and online.
- */
- int ONLINE = 3;
- }
-
- public interface AccountStatusColumns {
- /**
- * account id
- * <P>Type: INTEGER</P>
- */
- String ACCOUNT = "account";
-
- /**
- * User's presence status, see definitions in {#link CommonPresenceColumn}
- * <P>Type: INTEGER</P>
- */
- String PRESENCE_STATUS = "presenceStatus";
-
- /**
- * The connection status of this account, see {#link ConnectionStatus}
- * <P>Type: INTEGER</P>
- */
- String CONNECTION_STATUS = "connStatus";
- }
-
- public static final class AccountStatus implements BaseColumns, AccountStatusColumns {
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/accountStatus");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of account status.
- */
- public static final String CONTENT_TYPE =
- "vnd.android.cursor.dir/gtalk-account-status";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single account status.
- */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/gtalk-account-status";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER = "name ASC";
- }
-
- /**
- * Columns from the Contacts table.
- */
- public interface ContactsColumns {
- /**
- * The username
- * <P>Type: TEXT</P>
- */
- String USERNAME = "username";
-
- /**
- * The nickname or display name
- * <P>Type: TEXT</P>
- */
- String NICKNAME = "nickname";
-
- /**
- * The IM provider for this contact
- * <P>Type: INTEGER</P>
- */
- String PROVIDER = "provider";
-
- /**
- * The account (within a IM provider) for this contact
- * <P>Type: INTEGER</P>
- */
- String ACCOUNT = "account";
-
- /**
- * The contactList this contact belongs to
- * <P>Type: INTEGER</P>
- */
- String CONTACTLIST = "contactList";
-
- /**
- * Contact type
- * <P>Type: INTEGER</P>
- */
- String TYPE = "type";
-
- /**
- * normal IM contact
- */
- int TYPE_NORMAL = 0;
- /**
- * temporary contact, someone not in the list of contacts that we
- * subscribe presence for. Usually created because of the user is
- * having a chat session with this contact.
- */
- int TYPE_TEMPORARY = 1;
- /**
- * temporary contact created for group chat.
- */
- int TYPE_GROUP = 2;
- /**
- * blocked contact.
- */
- int TYPE_BLOCKED = 3;
- /**
- * the contact is hidden. The client should always display this contact to the user.
- */
- int TYPE_HIDDEN = 4;
- /**
- * the contact is pinned. The client should always display this contact to the user.
- */
- int TYPE_PINNED = 5;
-
- /**
- * Contact subscription status
- * <P>Type: INTEGER</P>
- */
- String SUBSCRIPTION_STATUS = "subscriptionStatus";
-
- /**
- * no pending subscription
- */
- int SUBSCRIPTION_STATUS_NONE = 0;
- /**
- * requested to subscribe
- */
- int SUBSCRIPTION_STATUS_SUBSCRIBE_PENDING = 1;
- /**
- * requested to unsubscribe
- */
- int SUBSCRIPTION_STATUS_UNSUBSCRIBE_PENDING = 2;
-
- /**
- * Contact subscription type
- * <P>Type: INTEGER </P>
- */
- String SUBSCRIPTION_TYPE = "subscriptionType";
-
- /**
- * The user and contact have no interest in each other's presence.
- */
- int SUBSCRIPTION_TYPE_NONE = 0;
- /**
- * The user wishes to stop receiving presence updates from the contact.
- */
- int SUBSCRIPTION_TYPE_REMOVE = 1;
- /**
- * The user is interested in receiving presence updates from the contact.
- */
- int SUBSCRIPTION_TYPE_TO = 2;
- /**
- * The contact is interested in receiving presence updates from the user.
- */
- int SUBSCRIPTION_TYPE_FROM = 3;
- /**
- * The user and contact have a mutual interest in each other's presence.
- */
- int SUBSCRIPTION_TYPE_BOTH = 4;
- /**
- * This is a special type reserved for pending subscription requests
- */
- int SUBSCRIPTION_TYPE_INVITATIONS = 5;
-
- /**
- * Quick Contact: derived from Google Contact Extension's "message_count" attribute.
- * <P>Type: INTEGER</P>
- */
- String QUICK_CONTACT = "qc";
-
- /**
- * Google Contact Extension attribute
- *
- * Rejected: a boolean value indicating whether a subscription request from
- * this client was ever rejected by the user. "true" indicates that it has.
- * This is provided so that a client can block repeated subscription requests.
- * <P>Type: INTEGER</P>
- */
- String REJECTED = "rejected";
-
- /**
- * Off The Record status: 0 for disabled, 1 for enabled
- * <P>Type: INTEGER </P>
- */
- String OTR = "otr";
- }
-
- /**
- * This defines the different type of values of {@link ContactsColumns#OTR}
- */
- public interface OffTheRecordType {
- /*
- * Off the record not turned on
- */
- int DISABLED = 0;
- /**
- * Off the record turned on, but we don't know who turned it on
- */
- int ENABLED = 1;
- /**
- * Off the record turned on by the user
- */
- int ENABLED_BY_USER = 2;
- /**
- * Off the record turned on by the buddy
- */
- int ENABLED_BY_BUDDY = 3;
- };
-
- /**
- * This table contains contacts.
- */
- public static final class Contacts implements BaseColumns,
- ContactsColumns, PresenceColumns, ChatsColumns {
- /**
- * no public constructor since this is a utility class
- */
- private Contacts() {}
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/contacts");
-
- /**
- * The content:// style URL for contacts joined with presence
- */
- public static final Uri CONTENT_URI_WITH_PRESENCE =
- Uri.parse("content://com.google.android.providers.talk/contactsWithPresence");
-
- /**
- * The content:// style URL for barebone contacts, not joined with any other table
- */
- public static final Uri CONTENT_URI_CONTACTS_BAREBONE =
- Uri.parse("content://com.google.android.providers.talk/contactsBarebone");
-
- /**
- * The content:// style URL for contacts who have an open chat session
- */
- public static final Uri CONTENT_URI_CHAT_CONTACTS =
- Uri.parse("content://com.google.android.providers.talk/contacts_chatting");
-
- /**
- * The content:// style URL for contacts who have been blocked
- */
- public static final Uri CONTENT_URI_BLOCKED_CONTACTS =
- Uri.parse("content://com.google.android.providers.talk/contacts/blocked");
-
- /**
- * The content:// style URL for contacts by provider and account
- */
- public static final Uri CONTENT_URI_CONTACTS_BY =
- Uri.parse("content://com.google.android.providers.talk/contacts");
-
- /**
- * The content:// style URL for contacts by provider and account,
- * and who have an open chat session
- */
- public static final Uri CONTENT_URI_CHAT_CONTACTS_BY =
- Uri.parse("content://com.google.android.providers.talk/contacts/chatting");
-
- /**
- * The content:// style URL for contacts by provider and account,
- * and who are online
- */
- public static final Uri CONTENT_URI_ONLINE_CONTACTS_BY =
- Uri.parse("content://com.google.android.providers.talk/contacts/online");
-
- /**
- * The content:// style URL for contacts by provider and account,
- * and who are offline
- */
- public static final Uri CONTENT_URI_OFFLINE_CONTACTS_BY =
- Uri.parse("content://com.google.android.providers.talk/contacts/offline");
-
- /**
- * The content:// style URL for operations on bulk contacts
- */
- public static final Uri BULK_CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/bulk_contacts");
-
- /**
- * The content:// style URL for the count of online contacts in each
- * contact list by provider and account.
- */
- public static final Uri CONTENT_URI_ONLINE_COUNT =
- Uri.parse("content://com.google.android.providers.talk/contacts/onlineCount");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * people.
- */
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/gtalk-contacts";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
- * person.
- */
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/gtalk-contacts";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER =
- "subscriptionType DESC, last_message_date DESC," +
- " mode DESC, nickname COLLATE UNICODE ASC";
-
- public static final String CHATS_CONTACT = "chats_contact";
-
- public static final String AVATAR_HASH = "avatars_hash";
-
- public static final String AVATAR_DATA = "avatars_data";
- }
-
- /**
- * Columns from the ContactList table.
- */
- public interface ContactListColumns {
- String NAME = "name";
- String PROVIDER = "provider";
- String ACCOUNT = "account";
- }
-
- /**
- * This table contains the contact lists.
- */
- public static final class ContactList implements BaseColumns,
- ContactListColumns {
- private ContactList() {}
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/contactLists");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * people.
- */
- public static final String CONTENT_TYPE =
- "vnd.android.cursor.dir/gtalk-contactLists";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
- * person.
- */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/gtalk-contactLists";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER = "name COLLATE UNICODE ASC";
-
- public static final String PROVIDER_NAME = "provider_name";
-
- public static final String ACCOUNT_NAME = "account_name";
- }
-
- /**
- * Columns from the BlockedList table.
- */
- public interface BlockedListColumns {
- /**
- * The username of the blocked contact.
- * <P>Type: TEXT</P>
- */
- String USERNAME = "username";
-
- /**
- * The nickname of the blocked contact.
- * <P>Type: TEXT</P>
- */
- String NICKNAME = "nickname";
-
- /**
- * The provider id of the blocked contact.
- * <P>Type: INT</P>
- */
- String PROVIDER = "provider";
-
- /**
- * The account id of the blocked contact.
- * <P>Type: INT</P>
- */
- String ACCOUNT = "account";
- }
-
- /**
- * This table contains blocked lists
- */
- public static final class BlockedList implements BaseColumns, BlockedListColumns {
- private BlockedList() {}
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/blockedList");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * people.
- */
- public static final String CONTENT_TYPE =
- "vnd.android.cursor.dir/gtalk-blockedList";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
- * person.
- */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/gtalk-blockedList";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER = "nickname ASC";
-
- public static final String PROVIDER_NAME = "provider_name";
-
- public static final String ACCOUNT_NAME = "account_name";
-
- public static final String AVATAR_DATA = "avatars_data";
- }
-
- /**
- * Columns from the contactsEtag table
- */
- public interface ContactsEtagColumns {
- /**
- * The roster etag, computed by the server, stored on the client. There is one etag
- * per account roster.
- * <P>Type: TEXT</P>
- */
- String ETAG = "etag";
-
- /**
- * The OTR etag, computed by the server, stored on the client. There is one OTR etag
- * per account roster.
- * <P>Type: TEXT</P>
- */
- String OTR_ETAG = "otr_etag";
-
- /**
- * The account id for the etag.
- * <P> Type: INTEGER </P>
- */
- String ACCOUNT = "account";
- }
-
- public static final class ContactsEtag implements BaseColumns, ContactsEtagColumns {
- private ContactsEtag() {}
-
- public static final Cursor query(ContentResolver cr,
- String[] projection) {
- return cr.query(CONTENT_URI, projection, null, null, null);
- }
-
- public static final Cursor query(ContentResolver cr,
- String[] projection, String where, String orderBy) {
- return cr.query(CONTENT_URI, projection, where,
- null, orderBy == null ? null : orderBy);
- }
-
- public static final String getRosterEtag(ContentResolver resolver, long accountId) {
- String retVal = null;
-
- Cursor c = resolver.query(CONTENT_URI,
- CONTACT_ETAG_PROJECTION,
- ACCOUNT + "=" + accountId,
- null /* selection args */,
- null /* sort order */);
-
- try {
- if (c.moveToFirst()) {
- retVal = c.getString(COLUMN_ETAG);
- }
- } finally {
- c.close();
- }
-
- return retVal;
- }
-
- public static final String getOtrEtag(ContentResolver resolver, long accountId) {
- String retVal = null;
-
- Cursor c = resolver.query(CONTENT_URI,
- CONTACT_OTR_ETAG_PROJECTION,
- ACCOUNT + "=" + accountId,
- null /* selection args */,
- null /* sort order */);
-
- try {
- if (c.moveToFirst()) {
- retVal = c.getString(COLUMN_OTR_ETAG);
- }
- } finally {
- c.close();
- }
-
- return retVal;
- }
-
- private static final String[] CONTACT_ETAG_PROJECTION = new String[] {
- Im.ContactsEtag.ETAG // 0
- };
-
- private static int COLUMN_ETAG = 0;
-
- private static final String[] CONTACT_OTR_ETAG_PROJECTION = new String[] {
- Im.ContactsEtag.OTR_ETAG // 0
- };
-
- private static int COLUMN_OTR_ETAG = 0;
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/contactsEtag");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * people.
- */
- public static final String CONTENT_TYPE =
- "vnd.android.cursor.dir/gtalk-contactsEtag";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
- * person.
- */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/gtalk-contactsEtag";
- }
-
- /**
- * Message type definition
- */
- public interface MessageType {
- /* sent message */
- int OUTGOING = 0;
- /* received message */
- int INCOMING = 1;
- /* presence became available */
- int PRESENCE_AVAILABLE = 2;
- /* presence became away */
- int PRESENCE_AWAY = 3;
- /* presence became DND (busy) */
- int PRESENCE_DND = 4;
- /* presence became unavailable */
- int PRESENCE_UNAVAILABLE = 5;
- /* the message is converted to a group chat */
- int CONVERT_TO_GROUPCHAT = 6;
- /* generic status */
- int STATUS = 7;
- /* the message cannot be sent now, but will be sent later */
- int POSTPONED = 8;
- /* off The Record status is turned off */
- int OTR_IS_TURNED_OFF = 9;
- /* off the record status is turned on */
- int OTR_IS_TURNED_ON = 10;
- /* off the record status turned on by user */
- int OTR_TURNED_ON_BY_USER = 11;
- /* off the record status turned on by buddy */
- int OTR_TURNED_ON_BY_BUDDY = 12;
- }
-
- /**
- * The common columns for messages table
- */
- public interface MessageColumns {
- /**
- * The thread_id column stores the contact id of the contact the message belongs to.
- * For groupchat messages, the thread_id stores the group id, which is the contact id
- * of the temporary group contact created for the groupchat. So there should be no
- * collision between groupchat message thread id and regular message thread id.
- */
- String THREAD_ID = "thread_id";
-
- /**
- * The nickname. This is used for groupchat messages to indicate the participant's
- * nickname. For non groupchat messages, this field should be left empty.
- */
- String NICKNAME = "nickname";
-
- /**
- * The body
- * <P>Type: TEXT</P>
- */
- String BODY = "body";
-
- /**
- * The date this message is sent or received. This represents the display date for
- * the message.
- * <P>Type: INTEGER</P>
- */
- String DATE = "date";
-
- /**
- * The real date for this message. While 'date' can be modified by the client
- * to account for server time skew, the real_date is the original timestamp set
- * by the server for incoming messages.
- * <P>Type: INTEGER</P>
- */
- String REAL_DATE = "real_date";
-
- /**
- * Message Type, see {@link MessageType}
- * <P>Type: INTEGER</P>
- */
- String TYPE = "type";
-
- /**
- * Error Code: 0 means no error.
- * <P>Type: INTEGER </P>
- */
- String ERROR_CODE = "err_code";
-
- /**
- * Error Message
- * <P>Type: TEXT</P>
- */
- String ERROR_MESSAGE = "err_msg";
-
- /**
- * Packet ID, auto assigned by the GTalkService for outgoing messages or the
- * GTalk server for incoming messages. The packet id field is optional for messages,
- * so it could be null.
- * <P>Type: STRING</P>
- */
- String PACKET_ID = "packet_id";
-
- /**
- * Is groupchat message or not
- * <P>Type: INTEGER</P>
- */
- String IS_GROUP_CHAT = "is_muc";
-
- /**
- * A hint that the UI should show the sent time of this message
- * <P>Type: INTEGER</P>
- */
- String DISPLAY_SENT_TIME = "show_ts";
-
- /*
- * For rows which have been consolidated this is the row id of the
- * row into which they have been consolidated.
- */
- String CONSOLIDATION_KEY = "consolidation_key";
- }
-
- /**
- * This table contains messages.
- */
- public static final class Messages implements BaseColumns, MessageColumns {
- /**
- * no public constructor since this is a utility class
- */
- private Messages() {}
-
- /**
- * Gets the Uri to query messages by thread id.
- *
- * @param threadId the thread id of the message.
- * @return the Uri
- */
- public static final Uri getContentUriByThreadId(long threadId) {
- Uri.Builder builder = CONTENT_URI_MESSAGES_BY_THREAD_ID.buildUpon();
- ContentUris.appendId(builder, threadId);
- return builder.build();
- }
-
- /**
- * @deprecated
- *
- * Gets the Uri to query messages by account and contact.
- *
- * @param accountId the account id of the contact.
- * @param username the user name of the contact.
- * @return the Uri
- */
- public static final Uri getContentUriByContact(long accountId, String username) {
- Uri.Builder builder = CONTENT_URI_MESSAGES_BY_ACCOUNT_AND_CONTACT.buildUpon();
- ContentUris.appendId(builder, accountId);
- builder.appendPath(username);
- return builder.build();
- }
-
- /**
- * Gets the Uri to query messages by provider.
- *
- * @param providerId the service provider id.
- * @return the Uri
- */
- public static final Uri getContentUriByProvider(long providerId) {
- Uri.Builder builder = CONTENT_URI_MESSAGES_BY_PROVIDER.buildUpon();
- ContentUris.appendId(builder, providerId);
- return builder.build();
- }
-
- /**
- * Gets the Uri to query off the record messages by account.
- *
- * @param accountId the account id.
- * @return the Uri
- */
- public static final Uri getContentUriByAccount(long accountId) {
- Uri.Builder builder = CONTENT_URI_BY_ACCOUNT.buildUpon();
- ContentUris.appendId(builder, accountId);
- return builder.build();
- }
-
- /**
- * Gets the Uri to query off the record messages by thread id.
- *
- * @param threadId the thread id of the message.
- * @return the Uri
- */
- public static final Uri getOtrMessagesContentUriByThreadId(long threadId) {
- Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_THREAD_ID.buildUpon();
- ContentUris.appendId(builder, threadId);
- return builder.build();
- }
-
- /**
- * @deprecated
- *
- * Gets the Uri to query off the record messages by account and contact.
- *
- * @param accountId the account id of the contact.
- * @param username the user name of the contact.
- * @return the Uri
- */
- public static final Uri getOtrMessagesContentUriByContact(long accountId, String username) {
- Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT_AND_CONTACT.buildUpon();
- ContentUris.appendId(builder, accountId);
- builder.appendPath(username);
- return builder.build();
- }
-
- /**
- * Gets the Uri to query off the record messages by provider.
- *
- * @param providerId the service provider id.
- * @return the Uri
- */
- public static final Uri getOtrMessagesContentUriByProvider(long providerId) {
- Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_PROVIDER.buildUpon();
- ContentUris.appendId(builder, providerId);
- return builder.build();
- }
-
- /**
- * Gets the Uri to query off the record messages by account.
- *
- * @param accountId the account id.
- * @return the Uri
- */
- public static final Uri getOtrMessagesContentUriByAccount(long accountId) {
- Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT.buildUpon();
- ContentUris.appendId(builder, accountId);
- return builder.build();
- }
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/messages");
-
- /**
- * The content:// style URL for messages by thread id
- */
- public static final Uri CONTENT_URI_MESSAGES_BY_THREAD_ID =
- Uri.parse("content://com.google.android.providers.talk/messagesByThreadId");
-
- /**
- * The content:// style URL for messages by account and contact
- */
- public static final Uri CONTENT_URI_MESSAGES_BY_ACCOUNT_AND_CONTACT =
- Uri.parse("content://com.google.android.providers.talk/messagesByAcctAndContact");
-
- /**
- * The content:// style URL for messages by provider
- */
- public static final Uri CONTENT_URI_MESSAGES_BY_PROVIDER =
- Uri.parse("content://com.google.android.providers.talk/messagesByProvider");
-
- /**
- * The content:// style URL for messages by account
- */
- public static final Uri CONTENT_URI_BY_ACCOUNT =
- Uri.parse("content://com.google.android.providers.talk/messagesByAccount");
-
- /**
- * The content:// style url for off the record messages
- */
- public static final Uri OTR_MESSAGES_CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/otrMessages");
-
- /**
- * The content:// style url for off the record messages by thread id
- */
- public static final Uri OTR_MESSAGES_CONTENT_URI_BY_THREAD_ID =
- Uri.parse("content://com.google.android.providers.talk/otrMessagesByThreadId");
-
- /**
- * The content:// style url for off the record messages by account and contact
- */
- public static final Uri OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT_AND_CONTACT =
- Uri.parse("content://com.google.android.providers.talk/otrMessagesByAcctAndContact");
-
- /**
- * The content:// style URL for off the record messages by provider
- */
- public static final Uri OTR_MESSAGES_CONTENT_URI_BY_PROVIDER =
- Uri.parse("content://com.google.android.providers.talk/otrMessagesByProvider");
-
- /**
- * The content:// style URL for off the record messages by account
- */
- public static final Uri OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT =
- Uri.parse("content://com.google.android.providers.talk/otrMessagesByAccount");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * people.
- */
- public static final String CONTENT_TYPE =
- "vnd.android.cursor.dir/gtalk-messages";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
- * person.
- */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/gtalk-messages";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER = "date ASC";
-
- /**
- * The "contact" column. This is not a real column in the messages table, but a
- * temoprary column created when querying for messages (joined with the contacts table)
- */
- public static final String CONTACT = "contact";
- }
-
- /**
- * Columns for the GroupMember table.
- */
- public interface GroupMemberColumns {
- /**
- * The id of the group this member belongs to.
- * <p>Type: INTEGER</p>
- */
- String GROUP = "groupId";
-
- /**
- * The full name of this member.
- * <p>Type: TEXT</p>
- */
- String USERNAME = "username";
-
- /**
- * The nick name of this member.
- * <p>Type: TEXT</p>
- */
- String NICKNAME = "nickname";
- }
-
- public final static class GroupMembers implements GroupMemberColumns {
- private GroupMembers(){}
-
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/groupMembers");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * group members.
- */
- public static final String CONTENT_TYPE =
- "vnd.android.cursor.dir/gtalk-groupMembers";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
- * group member.
- */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/gtalk-groupMembers";
- }
-
- /**
- * Columns from the Invitation table.
- */
- public interface InvitationColumns {
- /**
- * The provider id.
- * <p>Type: INTEGER</p>
- */
- String PROVIDER = "providerId";
-
- /**
- * The account id.
- * <p>Type: INTEGER</p>
- */
- String ACCOUNT = "accountId";
-
- /**
- * The invitation id.
- * <p>Type: TEXT</p>
- */
- String INVITE_ID = "inviteId";
-
- /**
- * The name of the sender of the invitation.
- * <p>Type: TEXT</p>
- */
- String SENDER = "sender";
-
- /**
- * The name of the group which the sender invite you to join.
- * <p>Type: TEXT</p>
- */
- String GROUP_NAME = "groupName";
-
- /**
- * A note
- * <p>Type: TEXT</p>
- */
- String NOTE = "note";
-
- /**
- * The current status of the invitation.
- * <p>Type: TEXT</p>
- */
- String STATUS = "status";
-
- int STATUS_PENDING = 0;
- int STATUS_ACCEPTED = 1;
- int STATUS_REJECTED = 2;
- }
-
- /**
- * This table contains the invitations received from others.
- */
- public final static class Invitation implements InvitationColumns,
- BaseColumns {
- private Invitation() {
- }
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/invitations");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * invitations.
- */
- public static final String CONTENT_TYPE =
- "vnd.android.cursor.dir/gtalk-invitations";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
- * invitation.
- */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/gtalk-invitations";
- }
-
- /**
- * Columns from the Avatars table
- */
- public interface AvatarsColumns {
- /**
- * The contact this avatar belongs to
- * <P>Type: TEXT</P>
- */
- String CONTACT = "contact";
-
- String PROVIDER = "provider_id";
-
- String ACCOUNT = "account_id";
-
- /**
- * The hash of the image data
- * <P>Type: TEXT</P>
- */
- String HASH = "hash";
-
- /**
- * raw image data
- * <P>Type: BLOB</P>
- */
- String DATA = "data";
- }
-
- /**
- * This table contains avatars.
- */
- public static final class Avatars implements BaseColumns, AvatarsColumns {
- /**
- * no public constructor since this is a utility class
- */
- private Avatars() {}
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/avatars");
-
- /**
- * The content:// style URL for avatars by provider, account and contact
- */
- public static final Uri CONTENT_URI_AVATARS_BY =
- Uri.parse("content://com.google.android.providers.talk/avatarsBy");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing the avatars
- */
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/gtalk-avatars";
-
- /**
- * The MIME type of a {@link #CONTENT_URI}
- */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/gtalk-avatars";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER = "contact ASC";
-
- }
-
- /**
- * Common presence columns shared between the IM and contacts presence tables
- */
- public interface CommonPresenceColumns {
- /**
- * The priority, an integer, used by XMPP presence
- * <P>Type: INTEGER</P>
- */
- String PRIORITY = "priority";
-
- /**
- * The server defined status.
- * <P>Type: INTEGER (one of the values below)</P>
- */
- String PRESENCE_STATUS = "mode";
-
- /**
- * Presence Status definition
- */
- int OFFLINE = 0;
- int INVISIBLE = 1;
- int AWAY = 2;
- int IDLE = 3;
- int DO_NOT_DISTURB = 4;
- int AVAILABLE = 5;
-
- /**
- * The user defined status line.
- * <P>Type: TEXT</P>
- */
- String PRESENCE_CUSTOM_STATUS = "status";
- }
-
- /**
- * Columns from the Presence table.
- */
- public interface PresenceColumns extends CommonPresenceColumns {
- /**
- * The contact id
- * <P>Type: INTEGER</P>
- */
- String CONTACT_ID = "contact_id";
-
- /**
- * The contact's JID resource, only relevant for XMPP contact
- * <P>Type: TEXT</P>
- */
- String JID_RESOURCE = "jid_resource";
-
- /**
- * The contact's client type
- */
- String CLIENT_TYPE = "client_type";
-
- /**
- * client type definitions
- */
- int CLIENT_TYPE_DEFAULT = 0;
- int CLIENT_TYPE_MOBILE = 1;
- int CLIENT_TYPE_ANDROID = 2;
- }
-
- /**
- * Contains presence infomation for contacts.
- */
- public static final class Presence implements BaseColumns, PresenceColumns {
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/presence");
-
- /**
- * The content URL for Talk presences for an account
- */
- public static final Uri CONTENT_URI_BY_ACCOUNT =
- Uri.parse("content://com.google.android.providers.talk/presence/account");
-
- /**
- * The content:// style URL for operations on bulk contacts
- */
- public static final Uri BULK_CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/bulk_presence");
-
- /**
- * The content:// style URL for seeding presences for a given account id.
- */
- public static final Uri SEED_PRESENCE_BY_ACCOUNT_CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/seed_presence/account");
-
- /**
- * The MIME type of a {@link #CONTENT_URI} providing a directory of presence
- */
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/gtalk-presence";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER = "mode DESC";
- }
-
- /**
- * Columns from the Chats table.
- */
- public interface ChatsColumns {
- /**
- * The contact ID this chat belongs to. The value is a long.
- * <P>Type: INT</P>
- */
- String CONTACT_ID = "contact_id";
-
- /**
- * The GTalk JID resource. The value is a string.
- * <P>Type: TEXT</P>
- */
- String JID_RESOURCE = "jid_resource";
-
- /**
- * Whether this is a groupchat or not.
- * <P>Type: INT</P>
- */
- String GROUP_CHAT = "groupchat";
-
- /**
- * The last unread message. This both indicates that there is an
- * unread message, and what the message is.
- * <P>Type: TEXT</P>
- */
- String LAST_UNREAD_MESSAGE = "last_unread_message";
-
- /**
- * The last message timestamp
- * <P>Type: INT</P>
- */
- String LAST_MESSAGE_DATE = "last_message_date";
-
- /**
- * A message that is being composed. This indicates that there was a
- * message being composed when the chat screen was shutdown, and what the
- * message is.
- * <P>Type: TEXT</P>
- */
- String UNSENT_COMPOSED_MESSAGE = "unsent_composed_message";
-
- /**
- * A value from 0-9 indicating which quick-switch chat screen slot this
- * chat is occupying. If none (for instance, this is the 12th active chat)
- * then the value is -1.
- * <P>Type: INT</P>
- */
- String SHORTCUT = "shortcut";
- }
-
- /**
- * Contains ongoing chat sessions.
- */
- public static final class Chats implements BaseColumns, ChatsColumns {
- /**
- * no public constructor since this is a utility class
- */
- private Chats() {}
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/chats");
-
- /**
- * The content URL for all chats that belong to the account
- */
- public static final Uri CONTENT_URI_BY_ACCOUNT =
- Uri.parse("content://com.google.android.providers.talk/chats/account");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of chats.
- */
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/gtalk-chats";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single chat.
- */
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/gtalk-chats";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER = "last_message_date ASC";
- }
-
- /**
- * Columns from session cookies table. Used for IMPS.
- */
- public static interface SessionCookiesColumns {
- String NAME = "name";
- String VALUE = "value";
- String PROVIDER = "provider";
- String ACCOUNT = "account";
- }
-
- /**
- * Contains IMPS session cookies.
- */
- public static class SessionCookies implements SessionCookiesColumns, BaseColumns {
- private SessionCookies() {
- }
-
- /**
- * The content:// style URI for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/sessionCookies");
-
- /**
- * The content:// style URL for session cookies by provider and account
- */
- public static final Uri CONTENT_URI_SESSION_COOKIES_BY =
- Uri.parse("content://com.google.android.providers.talk/sessionCookiesBy");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * people.
- */
- public static final String CONTENT_TYPE = "vnd.android-dir/gtalk-sessionCookies";
- }
-
- /**
- * Columns from ProviderSettings table
- */
- public static interface ProviderSettingsColumns {
- /**
- * The id in database of the related provider
- *
- * <P>Type: INT</P>
- */
- String PROVIDER = "provider";
-
- /**
- * The name of the setting
- * <P>Type: TEXT</P>
- */
- String NAME = "name";
-
- /**
- * The value of the setting
- * <P>Type: TEXT</P>
- */
- String VALUE = "value";
- }
-
- public static class ProviderSettings implements ProviderSettingsColumns {
- private ProviderSettings() {
- }
-
- /**
- * The content:// style URI for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/providerSettings");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing provider settings
- */
- public static final String CONTENT_TYPE = "vnd.android-dir/gtalk-providerSettings";
-
- /**
- * A boolean value to indicate whether this provider should show the offline contacts
- */
- public static final String SHOW_OFFLINE_CONTACTS = "show_offline_contacts";
-
- /** controls whether or not the GTalk service automatically connect to server. */
- public static final String SETTING_AUTOMATICALLY_CONNECT_GTALK = "gtalk_auto_connect";
-
- /** controls whether or not the GTalk service will be automatically started after boot */
- public static final String SETTING_AUTOMATICALLY_START_SERVICE = "auto_start_service";
-
- /** controls whether or not the offline contacts will be hided */
- public static final String SETTING_HIDE_OFFLINE_CONTACTS = "hide_offline_contacts";
-
- /** controls whether or not enable the GTalk notification */
- public static final String SETTING_ENABLE_NOTIFICATION = "enable_notification";
-
- /** specifies whether or not to vibrate */
- public static final String SETTING_VIBRATE = "vibrate";
-
- /** specifies the Uri string of the ringtone */
- public static final String SETTING_RINGTONE = "ringtone";
-
- /** specifies the Uri of the default ringtone */
- public static final String SETTING_RINGTONE_DEFAULT =
- "content://settings/system/notification_sound";
-
- /** specifies whether or not to show mobile indicator to friends */
- public static final String SETTING_SHOW_MOBILE_INDICATOR = "mobile_indicator";
-
- /** specifies whether or not to show as away when device is idle */
- public static final String SETTING_SHOW_AWAY_ON_IDLE = "show_away_on_idle";
-
- /** specifies whether or not to upload heartbeat stat upon login */
- public static final String SETTING_UPLOAD_HEARTBEAT_STAT = "upload_heartbeat_stat";
-
- /** specifies the last heartbeat interval received from the server */
- public static final String SETTING_HEARTBEAT_INTERVAL = "heartbeat_interval";
-
- /** specifiy the JID resource used for Google Talk connection */
- public static final String SETTING_JID_RESOURCE = "jid_resource";
-
- /**
- * Used for reliable message queue (RMQ). This is for storing the last rmq id received
- * from the GTalk server
- */
- public static final String LAST_RMQ_RECEIVED = "last_rmq_rec";
-
- /**
- * Query the settings of the provider specified by id
- *
- * @param cr
- * the relative content resolver
- * @param providerId
- * the specified id of provider
- * @return a HashMap which contains all the settings for the specified
- * provider
- */
- public static HashMap<String, String> queryProviderSettings(ContentResolver cr,
- long providerId) {
- HashMap<String, String> settings = new HashMap<String, String>();
-
- String[] projection = { NAME, VALUE };
- Cursor c = cr.query(ContentUris.withAppendedId(CONTENT_URI, providerId), projection, null, null, null);
- if (c == null) {
- return null;
- }
-
- while(c.moveToNext()) {
- settings.put(c.getString(0), c.getString(1));
- }
-
- c.close();
-
- return settings;
- }
-
- /**
- * Get the string value of setting which is specified by provider id and the setting name.
- *
- * @param cr The ContentResolver to use to access the settings table.
- * @param providerId The id of the provider.
- * @param settingName The name of the setting.
- * @return The value of the setting if the setting exist, otherwise return null.
- */
- public static String getStringValue(ContentResolver cr, long providerId, String settingName) {
- String ret = null;
- Cursor c = getSettingValue(cr, providerId, settingName);
- if (c != null) {
- ret = c.getString(0);
- c.close();
- }
-
- return ret;
- }
-
- /**
- * Get the boolean value of setting which is specified by provider id and the setting name.
- *
- * @param cr The ContentResolver to use to access the settings table.
- * @param providerId The id of the provider.
- * @param settingName The name of the setting.
- * @return The value of the setting if the setting exist, otherwise return false.
- */
- public static boolean getBooleanValue(ContentResolver cr, long providerId, String settingName) {
- boolean ret = false;
- Cursor c = getSettingValue(cr, providerId, settingName);
- if (c != null) {
- ret = c.getInt(0) != 0;
- c.close();
- }
- return ret;
- }
-
- private static Cursor getSettingValue(ContentResolver cr, long providerId, String settingName) {
- Cursor c = cr.query(ContentUris.withAppendedId(CONTENT_URI, providerId), new String[]{VALUE}, NAME + "=?",
- new String[]{settingName}, null);
- if (c != null) {
- if (!c.moveToFirst()) {
- c.close();
- return null;
- }
- }
- return c;
- }
-
- /**
- * Save a long value of setting in the table providerSetting.
- *
- * @param cr The ContentProvider used to access the providerSetting table.
- * @param providerId The id of the provider.
- * @param name The name of the setting.
- * @param value The value of the setting.
- */
- public static void putLongValue(ContentResolver cr, long providerId, String name,
- long value) {
- ContentValues v = new ContentValues(3);
- v.put(PROVIDER, providerId);
- v.put(NAME, name);
- v.put(VALUE, value);
-
- cr.insert(CONTENT_URI, v);
- }
-
- /**
- * Save a boolean value of setting in the table providerSetting.
- *
- * @param cr The ContentProvider used to access the providerSetting table.
- * @param providerId The id of the provider.
- * @param name The name of the setting.
- * @param value The value of the setting.
- */
- public static void putBooleanValue(ContentResolver cr, long providerId, String name,
- boolean value) {
- ContentValues v = new ContentValues(3);
- v.put(PROVIDER, providerId);
- v.put(NAME, name);
- v.put(VALUE, Boolean.toString(value));
-
- cr.insert(CONTENT_URI, v);
- }
-
- /**
- * Save a string value of setting in the table providerSetting.
- *
- * @param cr The ContentProvider used to access the providerSetting table.
- * @param providerId The id of the provider.
- * @param name The name of the setting.
- * @param value The value of the setting.
- */
- public static void putStringValue(ContentResolver cr, long providerId, String name,
- String value) {
- ContentValues v = new ContentValues(3);
- v.put(PROVIDER, providerId);
- v.put(NAME, name);
- v.put(VALUE, value);
-
- cr.insert(CONTENT_URI, v);
- }
-
- /**
- * A convenience method to set whether or not the GTalk service should be started
- * automatically.
- *
- * @param contentResolver The ContentResolver to use to access the settings table
- * @param autoConnect Whether the GTalk service should be started automatically.
- */
- public static void setAutomaticallyConnectGTalk(ContentResolver contentResolver,
- long providerId, boolean autoConnect) {
- putBooleanValue(contentResolver, providerId, SETTING_AUTOMATICALLY_CONNECT_GTALK,
- autoConnect);
- }
-
- /**
- * A convenience method to set whether or not the offline contacts should be hided
- *
- * @param contentResolver The ContentResolver to use to access the setting table
- * @param hideOfflineContacts Whether the offline contacts should be hided
- */
- public static void setHideOfflineContacts(ContentResolver contentResolver,
- long providerId, boolean hideOfflineContacts) {
- putBooleanValue(contentResolver, providerId, SETTING_HIDE_OFFLINE_CONTACTS,
- hideOfflineContacts);
- }
-
- /**
- * A convenience method to set whether or not enable the GTalk notification.
- *
- * @param contentResolver The ContentResolver to use to access the setting table.
- * @param enable Whether enable the GTalk notification
- */
- public static void setEnableNotification(ContentResolver contentResolver, long providerId,
- boolean enable) {
- putBooleanValue(contentResolver, providerId, SETTING_ENABLE_NOTIFICATION, enable);
- }
-
- /**
- * A convenience method to set whether or not to vibrate.
- *
- * @param contentResolver The ContentResolver to use to access the setting table.
- * @param vibrate Whether or not to vibrate
- */
- public static void setVibrate(ContentResolver contentResolver, long providerId,
- boolean vibrate) {
- putBooleanValue(contentResolver, providerId, SETTING_VIBRATE, vibrate);
- }
-
- /**
- * A convenience method to set the Uri String of the ringtone.
- *
- * @param contentResolver The ContentResolver to use to access the setting table.
- * @param ringtoneUri The Uri String of the ringtone to be set.
- */
- public static void setRingtoneURI(ContentResolver contentResolver, long providerId,
- String ringtoneUri) {
- putStringValue(contentResolver, providerId, SETTING_RINGTONE, ringtoneUri);
- }
-
- /**
- * A convenience method to set whether or not to show mobile indicator.
- *
- * @param contentResolver The ContentResolver to use to access the setting table.
- * @param showMobileIndicator Whether or not to show mobile indicator.
- */
- public static void setShowMobileIndicator(ContentResolver contentResolver, long providerId,
- boolean showMobileIndicator) {
- putBooleanValue(contentResolver, providerId, SETTING_SHOW_MOBILE_INDICATOR,
- showMobileIndicator);
- }
-
- /**
- * A convenience method to set whether or not to show as away when device is idle.
- *
- * @param contentResolver The ContentResolver to use to access the setting table.
- * @param showAway Whether or not to show as away when device is idle.
- */
- public static void setShowAwayOnIdle(ContentResolver contentResolver,
- long providerId, boolean showAway) {
- putBooleanValue(contentResolver, providerId, SETTING_SHOW_AWAY_ON_IDLE, showAway);
- }
-
- /**
- * A convenience method to set whether or not to upload heartbeat stat.
- *
- * @param contentResolver The ContentResolver to use to access the setting table.
- * @param uploadStat Whether or not to upload heartbeat stat.
- */
- public static void setUploadHeartbeatStat(ContentResolver contentResolver,
- long providerId, boolean uploadStat) {
- putBooleanValue(contentResolver, providerId, SETTING_UPLOAD_HEARTBEAT_STAT, uploadStat);
- }
-
- /**
- * A convenience method to set the heartbeat interval last received from the server.
- *
- * @param contentResolver The ContentResolver to use to access the setting table.
- * @param interval The heartbeat interval last received from the server.
- */
- public static void setHeartbeatInterval(ContentResolver contentResolver,
- long providerId, long interval) {
- putLongValue(contentResolver, providerId, SETTING_HEARTBEAT_INTERVAL, interval);
- }
-
- /**
- * A convenience method to set the jid resource.
- */
- public static void setJidResource(ContentResolver contentResolver,
- long providerId, String jidResource) {
- putStringValue(contentResolver, providerId, SETTING_JID_RESOURCE, jidResource);
- }
-
- public static class QueryMap extends ContentQueryMap {
- private ContentResolver mContentResolver;
- private long mProviderId;
-
- public QueryMap(ContentResolver contentResolver, long providerId, boolean keepUpdated,
- Handler handlerForUpdateNotifications) {
- super(contentResolver.query(CONTENT_URI,
- new String[] {NAME,VALUE},
- PROVIDER + "=" + providerId,
- null, // no selection args
- null), // no sort order
- NAME, keepUpdated, handlerForUpdateNotifications);
- mContentResolver = contentResolver;
- mProviderId = providerId;
- }
-
- /**
- * Set if the GTalk service should automatically connect to server.
- *
- * @param autoConnect if the GTalk service should auto connect to server.
- */
- public void setAutomaticallyConnectToGTalkServer(boolean autoConnect) {
- ProviderSettings.setAutomaticallyConnectGTalk(mContentResolver, mProviderId,
- autoConnect);
- }
-
- /**
- * Check if the GTalk service should automatically connect to server.
- * @return if the GTalk service should automatically connect to server.
- */
- public boolean getAutomaticallyConnectToGTalkServer() {
- return getBoolean(SETTING_AUTOMATICALLY_CONNECT_GTALK,
- true /* default to automatically sign in */);
- }
-
- /**
- * Set whether or not the offline contacts should be hided.
- *
- * @param hideOfflineContacts Whether or not the offline contacts should be hided.
- */
- public void setHideOfflineContacts(boolean hideOfflineContacts) {
- ProviderSettings.setHideOfflineContacts(mContentResolver, mProviderId,
- hideOfflineContacts);
- }
-
- /**
- * Check if the offline contacts should be hided.
- *
- * @return Whether or not the offline contacts should be hided.
- */
- public boolean getHideOfflineContacts() {
- return getBoolean(SETTING_HIDE_OFFLINE_CONTACTS,
- false/* by default not hide the offline contacts*/);
- }
-
- /**
- * Set whether or not enable the GTalk notification.
- *
- * @param enable Whether or not enable the GTalk notification.
- */
- public void setEnableNotification(boolean enable) {
- ProviderSettings.setEnableNotification(mContentResolver, mProviderId, enable);
- }
-
- /**
- * Check if the GTalk notification is enabled.
- *
- * @return Whether or not enable the GTalk notification.
- */
- public boolean getEnableNotification() {
- return getBoolean(SETTING_ENABLE_NOTIFICATION,
- true/* by default enable the notification */);
- }
-
- /**
- * Set whether or not to vibrate on GTalk notification.
- *
- * @param vibrate Whether or not to vibrate.
- */
- public void setVibrate(boolean vibrate) {
- ProviderSettings.setVibrate(mContentResolver, mProviderId, vibrate);
- }
-
- /**
- * Gets whether or not to vibrate on GTalk notification.
- *
- * @return Whether or not to vibrate.
- */
- public boolean getVibrate() {
- return getBoolean(SETTING_VIBRATE, false /* by default disable vibrate */);
- }
-
- /**
- * Set the Uri for the ringtone.
- *
- * @param ringtoneUri The Uri of the ringtone to be set.
- */
- public void setRingtoneURI(String ringtoneUri) {
- ProviderSettings.setRingtoneURI(mContentResolver, mProviderId, ringtoneUri);
- }
-
- /**
- * Get the Uri String of the current ringtone.
- *
- * @return The Uri String of the current ringtone.
- */
- public String getRingtoneURI() {
- return getString(SETTING_RINGTONE, SETTING_RINGTONE_DEFAULT);
- }
-
- /**
- * Set whether or not to show mobile indicator to friends.
- *
- * @param showMobile whether or not to show mobile indicator.
- */
- public void setShowMobileIndicator(boolean showMobile) {
- ProviderSettings.setShowMobileIndicator(mContentResolver, mProviderId, showMobile);
- }
-
- /**
- * Gets whether or not to show mobile indicator.
- *
- * @return Whether or not to show mobile indicator.
- */
- public boolean getShowMobileIndicator() {
- return getBoolean(SETTING_SHOW_MOBILE_INDICATOR,
- true /* by default show mobile indicator */);
- }
-
- /**
- * Set whether or not to show as away when device is idle.
- *
- * @param showAway whether or not to show as away when device is idle.
- */
- public void setShowAwayOnIdle(boolean showAway) {
- ProviderSettings.setShowAwayOnIdle(mContentResolver, mProviderId, showAway);
- }
-
- /**
- * Get whether or not to show as away when device is idle.
- *
- * @return Whether or not to show as away when device is idle.
- */
- public boolean getShowAwayOnIdle() {
- return getBoolean(SETTING_SHOW_AWAY_ON_IDLE,
- true /* by default show as away on idle*/);
- }
-
- /**
- * Set whether or not to upload heartbeat stat.
- *
- * @param uploadStat whether or not to upload heartbeat stat.
- */
- public void setUploadHeartbeatStat(boolean uploadStat) {
- ProviderSettings.setUploadHeartbeatStat(mContentResolver, mProviderId, uploadStat);
- }
-
- /**
- * Get whether or not to upload heartbeat stat.
- *
- * @return Whether or not to upload heartbeat stat.
- */
- public boolean getUploadHeartbeatStat() {
- return getBoolean(SETTING_UPLOAD_HEARTBEAT_STAT,
- false /* by default do not upload */);
- }
-
- /**
- * Set the last received heartbeat interval from the server.
- *
- * @param interval the last received heartbeat interval from the server.
- */
- public void setHeartbeatInterval(long interval) {
- ProviderSettings.setHeartbeatInterval(mContentResolver, mProviderId, interval);
- }
-
- /**
- * Get the last received heartbeat interval from the server.
- *
- * @return the last received heartbeat interval from the server.
- */
- public long getHeartbeatInterval() {
- return getLong(SETTING_HEARTBEAT_INTERVAL, 0L /* an invalid default interval */);
- }
-
- /**
- * Set the JID resource.
- *
- * @param jidResource the jid resource to be stored.
- */
- public void setJidResource(String jidResource) {
- ProviderSettings.setJidResource(mContentResolver, mProviderId, jidResource);
- }
- /**
- * Get the JID resource used for the Google Talk connection
- *
- * @return the JID resource stored.
- */
- public String getJidResource() {
- return getString(SETTING_JID_RESOURCE, null);
- }
-
- /**
- * Convenience function for retrieving a single settings value
- * as a boolean.
- *
- * @param name The name of the setting to retrieve.
- * @param def Value to return if the setting is not defined.
- * @return The setting's current value, or 'def' if it is not defined.
- */
- private boolean getBoolean(String name, boolean def) {
- ContentValues values = getValues(name);
- return values != null ? values.getAsBoolean(VALUE) : def;
- }
-
- /**
- * Convenience function for retrieving a single settings value
- * as a String.
- *
- * @param name The name of the setting to retrieve.
- * @param def The value to return if the setting is not defined.
- * @return The setting's current value or 'def' if it is not defined.
- */
- private String getString(String name, String def) {
- ContentValues values = getValues(name);
- return values != null ? values.getAsString(VALUE) : def;
- }
-
- /**
- * Convenience function for retrieving a single settings value
- * as an Integer.
- *
- * @param name The name of the setting to retrieve.
- * @param def The value to return if the setting is not defined.
- * @return The setting's current value or 'def' if it is not defined.
- */
- private int getInteger(String name, int def) {
- ContentValues values = getValues(name);
- return values != null ? values.getAsInteger(VALUE) : def;
- }
-
- /**
- * Convenience function for retrieving a single settings value
- * as a Long.
- *
- * @param name The name of the setting to retrieve.
- * @param def The value to return if the setting is not defined.
- * @return The setting's current value or 'def' if it is not defined.
- */
- private long getLong(String name, long def) {
- ContentValues values = getValues(name);
- return values != null ? values.getAsLong(VALUE) : def;
- }
- }
-
- }
-
-
- /**
- * Columns for GTalk branding resource map cache table. This table caches the result of
- * loading the branding resources to speed up GTalk landing page start.
- */
- public interface BrandingResourceMapCacheColumns {
- /**
- * The provider ID
- * <P>Type: INTEGER</P>
- */
- String PROVIDER_ID = "provider_id";
- /**
- * The application resource ID
- * <P>Type: INTEGER</P>
- */
- String APP_RES_ID = "app_res_id";
- /**
- * The plugin resource ID
- * <P>Type: INTEGER</P>
- */
- String PLUGIN_RES_ID = "plugin_res_id";
- }
-
- /**
- * The table for caching the result of loading GTalk branding resources.
- */
- public static final class BrandingResourceMapCache
- implements BaseColumns, BrandingResourceMapCacheColumns {
- /**
- * The content:// style URL for this table.
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/brandingResMapCache");
- }
-
-
-
- /**
- * //TODO: move these to MCS specific provider.
- * The following are MCS stuff, and should really live in a separate provider specific to
- * MCS code.
- */
-
- /**
- * Columns from OutgoingRmq table
- */
- public interface OutgoingRmqColumns {
- String RMQ_ID = "rmq_id";
- String TIMESTAMP = "ts";
- String DATA = "data";
- String PROTOBUF_TAG = "type";
- }
-
- /**
- * //TODO: we should really move these to their own provider and database.
- * The table for storing outgoing rmq packets.
- */
- public static final class OutgoingRmq implements BaseColumns, OutgoingRmqColumns {
- private static String[] RMQ_ID_PROJECTION = new String[] {
- RMQ_ID,
- };
-
- /**
- * queryHighestRmqId
- *
- * @param resolver the content resolver
- * @return the highest rmq id assigned to the rmq packet, or 0 if there are no rmq packets
- * in the OutgoingRmq table.
- */
- public static final long queryHighestRmqId(ContentResolver resolver) {
- Cursor cursor = resolver.query(Im.OutgoingRmq.CONTENT_URI_FOR_HIGHEST_RMQ_ID,
- RMQ_ID_PROJECTION,
- null, // selection
- null, // selection args
- null // sort
- );
-
- long retVal = 0;
- try {
- //if (DBG) log("initializeRmqid: cursor.count= " + cursor.count());
-
- if (cursor.moveToFirst()) {
- retVal = cursor.getLong(cursor.getColumnIndexOrThrow(RMQ_ID));
- }
- } finally {
- cursor.close();
- }
-
- return retVal;
- }
-
- /**
- * The content:// style URL for this table.
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/outgoingRmqMessages");
-
- /**
- * The content:// style URL for the highest rmq id for the outgoing rmq messages
- */
- public static final Uri CONTENT_URI_FOR_HIGHEST_RMQ_ID =
- Uri.parse("content://com.google.android.providers.talk/outgoingHighestRmqId");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "rmq_id ASC";
- }
-
- /**
- * Columns for the LastRmqId table, which stores a single row for the last client rmq id
- * sent to the server.
- */
- public interface LastRmqIdColumns {
- String RMQ_ID = "rmq_id";
- }
-
- /**
- * //TODO: move these out into their own provider and database
- * The table for storing the last client rmq id sent to the server.
- */
- public static final class LastRmqId implements BaseColumns, LastRmqIdColumns {
- private static String[] PROJECTION = new String[] {
- RMQ_ID,
- };
-
- /**
- * queryLastRmqId
- *
- * queries the last rmq id saved in the LastRmqId table.
- *
- * @param resolver the content resolver.
- * @return the last rmq id stored in the LastRmqId table, or 0 if not found.
- */
- public static final long queryLastRmqId(ContentResolver resolver) {
- Cursor cursor = resolver.query(Im.LastRmqId.CONTENT_URI,
- PROJECTION,
- null, // selection
- null, // selection args
- null // sort
- );
-
- long retVal = 0;
- try {
- if (cursor.moveToFirst()) {
- retVal = cursor.getLong(cursor.getColumnIndexOrThrow(RMQ_ID));
- }
- } finally {
- cursor.close();
- }
-
- return retVal;
- }
-
- /**
- * saveLastRmqId
- *
- * saves the rmqId to the lastRmqId table. This will override the existing row if any,
- * as we only keep one row of data in this table.
- *
- * @param resolver the content resolver.
- * @param rmqId the rmq id to be saved.
- */
- public static final void saveLastRmqId(ContentResolver resolver, long rmqId) {
- ContentValues values = new ContentValues();
-
- // always replace the first row.
- values.put(_ID, 1);
- values.put(RMQ_ID, rmqId);
- resolver.insert(CONTENT_URI, values);
- }
-
- /**
- * The content:// style URL for this table.
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/lastRmqId");
- }
-
- /**
- * Columns for the s2dRmqIds table, which stores the server-to-device message
- * persistent ids. These are used in the RMQ2 protocol, where in the login request, the
- * client selective acks these s2d ids to the server.
- */
- public interface ServerToDeviceRmqIdsColumn {
- String RMQ_ID = "rmq_id";
- }
-
- public static final class ServerToDeviceRmqIds implements BaseColumns,
- ServerToDeviceRmqIdsColumn {
-
- /**
- * The content:// style URL for this table.
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.google.android.providers.talk/s2dids");
- }
-
-}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index ae53dbe2..6d1fef6 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -179,6 +179,13 @@ public final class MediaStore {
public final static String EXTRA_OUTPUT = "output";
/**
+ * The string that is used when a media attribute is not known. For example,
+ * if an audio file does not have any meta data, the artist and album columns
+ * will be set to this value.
+ */
+ public static final String UNKNOWN_STRING = "<unknown>";
+
+ /**
* Common fields for most MediaProvider tables
*/
@@ -844,7 +851,6 @@ public final class MediaStore {
* The position, in ms, playback was at when playback for this file
* was last stopped.
* <P>Type: INTEGER (long)</P>
- * @hide
*/
public static final String BOOKMARK = "bookmark";
@@ -923,7 +929,6 @@ public final class MediaStore {
/**
* Non-zero if the audio file is a podcast
* <P>Type: INTEGER (boolean)</P>
- * @hide
*/
public static final String IS_PODCAST = "is_podcast";
@@ -964,7 +969,7 @@ public final class MediaStore {
public static String keyFor(String name) {
if (name != null) {
boolean sortfirst = false;
- if (name.equals(android.media.MediaFile.UNKNOWN_STRING)) {
+ if (name.equals(UNKNOWN_STRING)) {
return "\001";
}
// Check if the first character is \001. We use this to
@@ -1258,7 +1263,6 @@ public final class MediaStore {
* @param from The position of the item to move
* @param to The position to move the item to
* @return true on success
- * @hide
*/
public static final boolean moveItem(ContentResolver res,
long playlistId, int from, int to) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8c83303..112ea8f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1194,6 +1194,12 @@ public final class Settings {
public static final String VOLUME_NOTIFICATION = "volume_notification";
/**
+ * Bluetooth Headset volume. This is used internally, changing this value will
+ * not change the volume. See AudioManager.
+ */
+ public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
+
+ /**
* Whether the notifications should use the ring volume (value of 1) or
* a separate notification volume (value of 0). In most cases, users
* will have this enabled so the notification and ringer volumes will be
@@ -1214,7 +1220,7 @@ public final class Settings {
*/
public static final String[] VOLUME_SETTINGS = {
VOLUME_VOICE, VOLUME_SYSTEM, VOLUME_RING, VOLUME_MUSIC,
- VOLUME_ALARM, VOLUME_NOTIFICATION
+ VOLUME_ALARM, VOLUME_NOTIFICATION, VOLUME_BLUETOOTH_SCO
};
/**
@@ -1447,7 +1453,6 @@ public final class Settings {
*/
public static final String[] SETTINGS_TO_BACKUP = {
STAY_ON_WHILE_PLUGGED_IN,
- END_BUTTON_BEHAVIOR,
WIFI_SLEEP_POLICY,
WIFI_USE_STATIC_IP,
WIFI_STATIC_IP,
@@ -1472,12 +1477,14 @@ public final class Settings {
VOLUME_MUSIC,
VOLUME_ALARM,
VOLUME_NOTIFICATION,
+ VOLUME_BLUETOOTH_SCO,
VOLUME_VOICE + APPEND_FOR_LAST_AUDIBLE,
VOLUME_SYSTEM + APPEND_FOR_LAST_AUDIBLE,
VOLUME_RING + APPEND_FOR_LAST_AUDIBLE,
VOLUME_MUSIC + APPEND_FOR_LAST_AUDIBLE,
VOLUME_ALARM + APPEND_FOR_LAST_AUDIBLE,
VOLUME_NOTIFICATION + APPEND_FOR_LAST_AUDIBLE,
+ VOLUME_BLUETOOTH_SCO + APPEND_FOR_LAST_AUDIBLE,
TEXT_AUTO_REPLACE,
TEXT_AUTO_CAPS,
TEXT_AUTO_PUNCTUATE,
@@ -3711,6 +3718,11 @@ public final class Settings {
"dropbox:";
/**
+ * Nonzero causes Log.wtf() to crash.
+ */
+ public static final String WTF_IS_FATAL = "wtf_is_fatal";
+
+ /**
* The length of time in milli-seconds that automatic small adjustments to
* SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded.
*/
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index f2e132b..816ae14 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -96,11 +96,13 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
BluetoothDevice.ERROR);
switch(bondState) {
case BluetoothDevice.BOND_BONDED:
- setSinkPriority(device, BluetoothA2dp.PRIORITY_ON);
+ if (getSinkPriority(device) == BluetoothA2dp.PRIORITY_UNDEFINED) {
+ setSinkPriority(device, BluetoothA2dp.PRIORITY_ON);
+ }
break;
case BluetoothDevice.BOND_BONDING:
case BluetoothDevice.BOND_NONE:
- setSinkPriority(device, BluetoothA2dp.PRIORITY_OFF);
+ setSinkPriority(device, BluetoothA2dp.PRIORITY_UNDEFINED);
break;
}
} else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
@@ -305,7 +307,11 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return false;
// State is DISCONNECTED
+ handleSinkStateChange(device, state, BluetoothA2dp.STATE_CONNECTING);
+
if (!connectSinkNative(path)) {
+ // Restore previous state
+ handleSinkStateChange(device, mAudioDevices.get(device), state);
return false;
}
return true;
@@ -321,7 +327,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return false;
}
- switch (getSinkState(device)) {
+ int state = getSinkState(device);
+ switch (state) {
case BluetoothA2dp.STATE_DISCONNECTED:
return false;
case BluetoothA2dp.STATE_DISCONNECTING:
@@ -329,11 +336,13 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
}
// State is CONNECTING or CONNECTED or PLAYING
+ handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTING);
if (!disconnectSinkNative(path)) {
+ // Restore previous state
+ handleSinkStateChange(device, mAudioDevices.get(device), state);
return false;
- } else {
- return true;
}
+ return true;
}
public synchronized boolean suspendSink(BluetoothDevice device) {
@@ -512,6 +521,19 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return result;
}
+ private void onConnectSinkResult(String deviceObjectPath, boolean result) {
+ // If the call was a success, ignore we will update the state
+ // when we a Sink Property Change
+ if (!result) {
+ if (deviceObjectPath != null) {
+ String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+ int state = getSinkState(device);
+ handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED);
+ }
+ }
+ }
+
@Override
protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mAudioDevices.isEmpty()) return;
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 0d0d245..b28cf43 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -21,14 +21,15 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothUuid;
-import android.os.ParcelUuid;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
+import android.os.ParcelUuid;
import android.util.Log;
import java.util.HashMap;
+import java.util.Set;
/**
* TODO: Move this to
@@ -553,7 +554,7 @@ class BluetoothEventLoop {
if (mBluetoothService.isEnabled() &&
(BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid)
|| BluetoothUuid.isAdvAudioDist(uuid)) &&
- (a2dp.getNonDisconnectedSinks().size() == 0)) {
+ !isOtherSinkInNonDisconnectingState(address)) {
BluetoothDevice device = mAdapter.getRemoteDevice(address);
authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF;
if (authorized) {
@@ -568,6 +569,16 @@ class BluetoothEventLoop {
return authorized;
}
+ boolean isOtherSinkInNonDisconnectingState(String address) {
+ BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
+ Set<BluetoothDevice> devices = a2dp.getNonDisconnectedSinks();
+ if (devices.size() == 0) return false;
+ for(BluetoothDevice dev: devices) {
+ if (!dev.getAddress().equals(address)) return true;
+ }
+ return false;
+ }
+
private void onAgentCancel() {
Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index b590449..dfb775f 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -74,6 +74,7 @@ public class BluetoothService extends IBluetooth.Stub {
private int mNativeData;
private BluetoothEventLoop mEventLoop;
private boolean mIsAirplaneSensitive;
+ private boolean mIsAirplaneToggleable;
private int mBluetoothState;
private boolean mRestart = false; // need to call enable() after disable()
private boolean mIsDiscovering;
@@ -370,7 +371,7 @@ public class BluetoothService extends IBluetooth.Stub {
"Need BLUETOOTH_ADMIN permission");
// Airplane mode can prevent Bluetooth radio from being turned on.
- if (mIsAirplaneSensitive && isAirplaneModeOn()) {
+ if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
return false;
}
if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
@@ -545,7 +546,7 @@ public class BluetoothService extends IBluetooth.Stub {
mEventLoop.onPropertyChanged(propVal);
}
- if (mIsAirplaneSensitive && isAirplaneModeOn()) {
+ if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
disable(false);
}
@@ -1597,10 +1598,17 @@ public class BluetoothService extends IBluetooth.Stub {
};
private void registerForAirplaneMode(IntentFilter filter) {
- String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
+ final ContentResolver resolver = mContext.getContentResolver();
+ final String airplaneModeRadios = Settings.System.getString(resolver,
Settings.System.AIRPLANE_MODE_RADIOS);
- mIsAirplaneSensitive = airplaneModeRadios == null
- ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
+ final String toggleableRadios = Settings.System.getString(resolver,
+ Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+
+ mIsAirplaneSensitive = airplaneModeRadios == null ? true :
+ airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
+ mIsAirplaneToggleable = toggleableRadios == null ? false :
+ toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
+
if (mIsAirplaneSensitive) {
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
}
@@ -1661,6 +1669,7 @@ public class BluetoothService extends IBluetooth.Stub {
}
pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
+ pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
pw.println("Local address = " + getAddress());
pw.println("Local name = " + getName());
diff --git a/core/java/android/text/AutoText.java b/core/java/android/text/AutoText.java
index 2fc906a..862305b 100644
--- a/core/java/android/text/AutoText.java
+++ b/core/java/android/text/AutoText.java
@@ -18,7 +18,7 @@ package android.text;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
import android.view.View;
import org.xmlpull.v1.XmlPullParser;
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 380e5fd..33ecc01 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -46,7 +46,7 @@ import android.text.style.TypefaceSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
import android.util.Log;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
import java.io.IOException;
import java.io.StringReader;
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 0d04b13..7b307f8 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -247,10 +247,11 @@ implements MovementMethod
KeyEvent.META_SHIFT_ON) == 1) ||
(MetaKeyKeyListener.getMetaState(buffer,
MetaKeyKeyListener.META_SELECTING) != 0);
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+ int offset = getOffset(x, y, widget);
+
if (cap) {
- int x = (int) event.getX();
- int y = (int) event.getY();
- int offset = getOffset(x, y, widget);
buffer.setSpan(LAST_TAP_DOWN, offset, offset,
Spannable.SPAN_POINT_POINT);
@@ -260,6 +261,30 @@ implements MovementMethod
// without this, users would get booted out of select
// mode once the view detected it needed to scroll.
widget.getParent().requestDisallowInterceptTouchEvent(true);
+ } else {
+ OnePointFiveTapState[] tap = buffer.getSpans(0, buffer.length(),
+ OnePointFiveTapState.class);
+
+ if (tap.length > 0) {
+ if (event.getEventTime() - tap[0].mWhen <=
+ ViewConfiguration.getDoubleTapTimeout() &&
+ sameWord(buffer, offset, Selection.getSelectionEnd(buffer))) {
+
+ tap[0].active = true;
+ MetaKeyKeyListener.startSelecting(widget, buffer);
+ widget.getParent().requestDisallowInterceptTouchEvent(true);
+ buffer.setSpan(LAST_TAP_DOWN, offset, offset,
+ Spannable.SPAN_POINT_POINT);
+ }
+
+ tap[0].mWhen = event.getEventTime();
+ } else {
+ OnePointFiveTapState newtap = new OnePointFiveTapState();
+ newtap.mWhen = event.getEventTime();
+ newtap.active = false;
+ buffer.setSpan(newtap, 0, buffer.length(),
+ Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+ }
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE ) {
boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
@@ -287,7 +312,7 @@ implements MovementMethod
// user started the selection)
int lastDownOffset = buffer.getSpanStart(LAST_TAP_DOWN);
- // Compute the selection boundries
+ // Compute the selection boundaries
int spanstart;
int spanend;
if (offset >= lastDownOffset) {
@@ -324,6 +349,19 @@ implements MovementMethod
// XXX should do the same adjust for x as we do for the line.
+ OnePointFiveTapState[] onepointfivetap = buffer.getSpans(0, buffer.length(),
+ OnePointFiveTapState.class);
+ if (onepointfivetap.length > 0 && onepointfivetap[0].active &&
+ Selection.getSelectionStart(buffer) == Selection.getSelectionEnd(buffer)) {
+ // If we've set select mode, because there was a onepointfivetap,
+ // but there was no ensuing swipe gesture, undo the select mode
+ // and remove reference to the last onepointfivetap.
+ MetaKeyKeyListener.stopSelecting(widget, buffer);
+ for (int i=0; i < onepointfivetap.length; i++) {
+ buffer.removeSpan(onepointfivetap[i]);
+ }
+ buffer.removeSpan(LAST_TAP_DOWN);
+ }
boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
KeyEvent.META_SHIFT_ON) == 1) ||
(MetaKeyKeyListener.getMetaState(buffer,
@@ -335,10 +373,10 @@ implements MovementMethod
if (tap.length > 0) {
if (event.getEventTime() - tap[0].mWhen <=
- ViewConfiguration.getDoubleTapTimeout()) {
- if (sameWord(buffer, off, Selection.getSelectionEnd(buffer))) {
- doubletap = true;
- }
+ ViewConfiguration.getDoubleTapTimeout() &&
+ sameWord(buffer, off, Selection.getSelectionEnd(buffer))) {
+
+ doubletap = true;
}
tap[0].mWhen = event.getEventTime();
@@ -351,6 +389,11 @@ implements MovementMethod
if (cap) {
buffer.removeSpan(LAST_TAP_DOWN);
+ if (onepointfivetap.length > 0 && onepointfivetap[0].active) {
+ // If we selecting something with the onepointfivetap-and
+ // swipe gesture, stop it on finger up.
+ MetaKeyKeyListener.stopSelecting(widget, buffer);
+ }
} else if (doubletap) {
Selection.setSelection(buffer,
findWordStart(buffer, off),
@@ -373,6 +416,19 @@ implements MovementMethod
long mWhen;
}
+ /* We check for a onepointfive tap. This is similar to
+ * doubletap gesture (where a finger goes down, up, down, up, in a short
+ * time period), except in the onepointfive tap, a users finger only needs
+ * to go down, up, down in a short time period. We detect this type of tap
+ * to implement the onepointfivetap-and-swipe selection gesture.
+ * This gesture allows users to select a segment of text without going
+ * through the "select text" option in the context menu.
+ */
+ private static class OnePointFiveTapState implements NoCopySpan {
+ long mWhen;
+ boolean active;
+ }
+
private static boolean sameWord(CharSequence text, int one, int two) {
int start = findWordStart(text, one);
int end = findWordEnd(text, one);
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 81dd96e..ce0b954 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -16,134 +16,43 @@
package android.util;
-import com.google.android.collect.Lists;
-
+import java.io.BufferedReader;
+import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
+import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
- * {@hide}
- * Dynamically defined (in terms of event types), space efficient (i.e. "tight") event logging
- * to help instrument code for large scale stability and performance monitoring.
- *
- * Note that this class contains all static methods. This is done for efficiency reasons.
+ * Access to the system diagnostic event record. System diagnostic events are
+ * used to record certain system-level events (such as garbage collection,
+ * activity manager state, system watchdogs, and other low level activity),
+ * which may be automatically collected and analyzed during system development.
*
- * Events for the event log are self-describing binary data structures. They start with a 20 byte
- * header (generated automatically) which contains all of the following in order:
+ * <p>This is <b>not</b> the main "logcat" debugging log ({@link android.util.Log})!
+ * These diagnostic events are for system integrators, not application authors.
*
- * <ul>
- * <li> Payload length: 2 bytes - length of the non-header portion </li>
- * <li> Padding: 2 bytes - no meaning at this time </li>
- * <li> Timestamp:
- * <ul>
- * <li> Seconds: 4 bytes - seconds since Epoch </li>
- * <li> Nanoseconds: 4 bytes - plus extra nanoseconds </li>
- * </ul></li>
- * <li> Process ID: 4 bytes - matching {@link android.os.Process#myPid} </li>
- * <li> Thread ID: 4 bytes - matching {@link android.os.Process#myTid} </li>
- * </li>
- * </ul>
+ * <p>Events use integer tag codes corresponding to /system/etc/event-log-tags.
+ * They carry a payload of one or more int, long, or String values. The
+ * event-log-tags file defines the payload contents for each type code.
*
- * The above is followed by a payload, comprised of the following:
- * <ul>
- * <li> Tag: 4 bytes - unique integer used to identify a particular event. This number is also
- * used as a key to map to a string that can be displayed by log reading tools.
- * </li>
- * <li> Type: 1 byte - can be either {@link #INT}, {@link #LONG}, {@link #STRING},
- * or {@link #LIST}. </li>
- * <li> Event log value: the size and format of which is one of:
- * <ul>
- * <li> INT: 4 bytes </li>
- * <li> LONG: 8 bytes </li>
- * <li> STRING:
- * <ul>
- * <li> Size of STRING: 4 bytes </li>
- * <li> The string: n bytes as specified in the size fields above. </li>
- * </ul></li>
- * <li> {@link List LIST}:
- * <ul>
- * <li> Num items: 1 byte </li>
- * <li> N value payloads, where N is the number of items specified above. </li>
- * </ul></li>
- * </ul>
- * </li>
- * <li> '\n': 1 byte - an automatically generated newline, used to help detect and recover from log
- * corruption and enable standard unix tools like grep, tail and wc to operate
- * on event logs. </li>
- * </ul>
- *
- * Note that all output is done in the endian-ness of the device (as determined
- * by {@link ByteOrder#nativeOrder()}).
+ * @pending
*/
-
public class EventLog {
+ private static final String TAG = "EventLog";
- // Value types
- public static final byte INT = 0;
- public static final byte LONG = 1;
- public static final byte STRING = 2;
- public static final byte LIST = 3;
+ private static final String TAGS_FILE = "/system/etc/event-log-tags";
+ private static final String COMMENT_PATTERN = "^\\s*(#.*)?$";
+ private static final String TAG_PATTERN = "^\\s*(\\d+)\\s+(\\w+)\\s*(\\(.*\\))?\\s*$";
+ private static HashMap<String, Integer> sTagCodes = null;
+ private static HashMap<Integer, String> sTagNames = null;
- /**
- * An immutable tuple used to log a heterogeneous set of loggable items.
- * The items can be Integer, Long, String, or {@link List}.
- * The maximum number of items is 127
- */
- public static final class List {
- private Object[] mItems;
-
- /**
- * Get a particular tuple item
- * @param pos The position of the item in the tuple
- */
- public final Object getItem(int pos) {
- return mItems[pos];
- }
-
- /**
- * Get the number of items in the tuple.
- */
- public final byte getNumItems() {
- return (byte) mItems.length;
- }
-
- /**
- * Create a new tuple.
- * @param items The items to create the tuple with, as varargs.
- * @throws IllegalArgumentException if the arguments are too few (0),
- * too many, or aren't loggable types.
- */
- public List(Object... items) throws IllegalArgumentException {
- if (items.length > Byte.MAX_VALUE) {
- throw new IllegalArgumentException(
- "A List must have fewer than "
- + Byte.MAX_VALUE + " items in it.");
- }
- for (int i = 0; i < items.length; i++) {
- final Object item = items[i];
- if (item == null) {
- // Would be nice to be able to write null strings...
- items[i] = "";
- } else if (!(item instanceof List ||
- item instanceof String ||
- item instanceof Integer ||
- item instanceof Long)) {
- throw new IllegalArgumentException(
- "Attempt to create a List with illegal item type.");
- }
- }
- this.mItems = items;
- }
- }
-
- /**
- * A previously logged event read from the logs.
- */
+ /** A previously logged event read from the logs. */
public static final class Event {
private final ByteBuffer mBuffer;
@@ -158,77 +67,83 @@ public class EventLog {
private static final int TAG_OFFSET = 20;
private static final int DATA_START = 24;
+ // Value types
+ private static final byte INT_TYPE = 0;
+ private static final byte LONG_TYPE = 1;
+ private static final byte STRING_TYPE = 2;
+ private static final byte LIST_TYPE = 3;
+
/** @param data containing event, read from the system */
- public Event(byte[] data) {
+ /*package*/ Event(byte[] data) {
mBuffer = ByteBuffer.wrap(data);
mBuffer.order(ByteOrder.nativeOrder());
}
+ /** @return the process ID which wrote the log entry */
public int getProcessId() {
return mBuffer.getInt(PROCESS_OFFSET);
}
+ /** @return the thread ID which wrote the log entry */
public int getThreadId() {
return mBuffer.getInt(THREAD_OFFSET);
}
+ /** @return the wall clock time when the entry was written */
public long getTimeNanos() {
return mBuffer.getInt(SECONDS_OFFSET) * 1000000000l
+ mBuffer.getInt(NANOSECONDS_OFFSET);
}
+ /** @return the type tag code of the entry */
public int getTag() {
return mBuffer.getInt(TAG_OFFSET);
}
- /** @return one of Integer, Long, String, or List. */
+ /** @return one of Integer, Long, String, null, or Object[] of same. */
public synchronized Object getData() {
- mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET));
- mBuffer.position(DATA_START); // Just after the tag.
- return decodeObject();
- }
-
- public byte[] getRawData() {
- return mBuffer.array();
+ try {
+ mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET));
+ mBuffer.position(DATA_START); // Just after the tag.
+ return decodeObject();
+ } catch (IllegalArgumentException e) {
+ Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e);
+ return null;
+ } catch (BufferUnderflowException e) {
+ Log.wtf(TAG, "Truncated entry payload: tag=" + getTag(), e);
+ return null;
+ }
}
/** @return the loggable item at the current position in mBuffer. */
private Object decodeObject() {
- if (mBuffer.remaining() < 1) return null;
- switch (mBuffer.get()) {
- case INT:
- if (mBuffer.remaining() < 4) return null;
+ byte type = mBuffer.get();
+ switch (type) {
+ case INT_TYPE:
return (Integer) mBuffer.getInt();
- case LONG:
- if (mBuffer.remaining() < 8) return null;
+ case LONG_TYPE:
return (Long) mBuffer.getLong();
- case STRING:
+ case STRING_TYPE:
try {
- if (mBuffer.remaining() < 4) return null;
int length = mBuffer.getInt();
- if (length < 0 || mBuffer.remaining() < length) return null;
int start = mBuffer.position();
mBuffer.position(start + length);
return new String(mBuffer.array(), start, length, "UTF-8");
} catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e); // UTF-8 is guaranteed.
+ Log.wtf(TAG, "UTF-8 is not supported", e);
+ return null;
}
- case LIST:
- if (mBuffer.remaining() < 1) return null;
+ case LIST_TYPE:
int length = mBuffer.get();
- if (length < 0) return null;
Object[] array = new Object[length];
- for (int i = 0; i < length; ++i) {
- array[i] = decodeObject();
- if (array[i] == null) return null;
- }
- return new List(array);
+ for (int i = 0; i < length; ++i) array[i] = decodeObject();
+ return array;
default:
- return null;
+ throw new IllegalArgumentException("Unknown entry type: " + type);
}
}
}
@@ -236,46 +151,36 @@ public class EventLog {
// We assume that the native methods deal with any concurrency issues.
/**
- * Send an event log message.
- * @param tag An event identifer
+ * Record an event log message.
+ * @param tag The event type tag code
* @param value A value to log
* @return The number of bytes written
*/
public static native int writeEvent(int tag, int value);
/**
- * Send an event log message.
- * @param tag An event identifer
+ * Record an event log message.
+ * @param tag The event type tag code
* @param value A value to log
* @return The number of bytes written
*/
public static native int writeEvent(int tag, long value);
/**
- * Send an event log message.
- * @param tag An event identifer
+ * Record an event log message.
+ * @param tag The event type tag code
* @param str A value to log
* @return The number of bytes written
*/
public static native int writeEvent(int tag, String str);
/**
- * Send an event log message.
- * @param tag An event identifer
- * @param list A {@link List} to log
- * @return The number of bytes written
- */
- public static native int writeEvent(int tag, List list);
-
- /**
- * Send an event log message.
- * @param tag An event identifer
+ * Record an event log message.
+ * @param tag The event type tag code
* @param list A list of values to log
* @return The number of bytes written
*/
- public static int writeEvent(int tag, Object... list) {
- return writeEvent(tag, new List(list));
- }
+ public static native int writeEvent(int tag, Object... list);
/**
* Read events from the log, filtered by type.
@@ -287,11 +192,65 @@ public class EventLog {
throws IOException;
/**
- * Read events from a file.
- * @param path to read from
- * @param output container to add events into
- * @throws IOException if something goes wrong reading events
+ * Get the name associated with an event type tag code.
+ * @param tag code to look up
+ * @return the name of the tag, or null if no tag has that number
*/
- public static native void readEvents(String path, Collection<Event> output)
- throws IOException;
+ public static String getTagName(int tag) {
+ readTagsFile();
+ return sTagNames.get(tag);
+ }
+
+ /**
+ * Get the event type tag code associated with an event name.
+ * @param name of event to look up
+ * @return the tag code, or -1 if no tag has that name
+ */
+ public static int getTagCode(String name) {
+ readTagsFile();
+ Integer code = sTagCodes.get(name);
+ return code != null ? code : -1;
+ }
+
+ /**
+ * Read TAGS_FILE, populating sTagCodes and sTagNames, if not already done.
+ */
+ private static synchronized void readTagsFile() {
+ if (sTagCodes != null && sTagNames != null) return;
+
+ sTagCodes = new HashMap<String, Integer>();
+ sTagNames = new HashMap<Integer, String>();
+
+ Pattern comment = Pattern.compile(COMMENT_PATTERN);
+ Pattern tag = Pattern.compile(TAG_PATTERN);
+ BufferedReader reader = null;
+ String line;
+
+ try {
+ reader = new BufferedReader(new FileReader(TAGS_FILE), 256);
+ while ((line = reader.readLine()) != null) {
+ if (comment.matcher(line).matches()) continue;
+
+ Matcher m = tag.matcher(line);
+ if (!m.matches()) {
+ Log.wtf(TAG, "Bad entry in " + TAGS_FILE + ": " + line);
+ continue;
+ }
+
+ try {
+ int num = Integer.parseInt(m.group(1));
+ String name = m.group(2);
+ sTagCodes.put(name, num);
+ sTagNames.put(num, name);
+ } catch (NumberFormatException e) {
+ Log.wtf(TAG, "Error in " + TAGS_FILE + ": " + line, e);
+ }
+ }
+ } catch (IOException e) {
+ Log.wtf(TAG, "Error reading " + TAGS_FILE, e);
+ // Leave the maps existing but unpopulated
+ } finally {
+ try { if (reader != null) reader.close(); } catch (IOException e) {}
+ }
+ }
}
diff --git a/core/java/android/util/EventLogTags.java b/core/java/android/util/EventLogTags.java
index be905e3..075c84e 100644
--- a/core/java/android/util/EventLogTags.java
+++ b/core/java/android/util/EventLogTags.java
@@ -25,16 +25,14 @@ import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-/** Parsed representation of /etc/event-log-tags. */
+/**
+ * to-be-deprecated: This class is no longer functional.
+ * Use {to-be-link android.util.EventLog} instead.
+ */
public class EventLogTags {
- private final static String TAG = "EventLogTags";
-
- private final static String TAGS_FILE = "/etc/event-log-tags";
-
public static class Description {
public final int mTag;
public final String mName;
- // TODO: Parse parameter descriptions when anyone has a use for them.
Description(int tag, String name) {
mTag = tag;
@@ -42,49 +40,11 @@ public class EventLogTags {
}
}
- private final static Pattern COMMENT_PATTERN = Pattern.compile(
- "^\\s*(#.*)?$");
-
- private final static Pattern TAG_PATTERN = Pattern.compile(
- "^\\s*(\\d+)\\s+(\\w+)\\s*(\\(.*\\))?\\s*$");
+ public EventLogTags() throws IOException {}
- private final HashMap<String, Description> mNameMap =
- new HashMap<String, Description>();
-
- private final HashMap<Integer, Description> mTagMap =
- new HashMap<Integer, Description>();
-
- public EventLogTags() throws IOException {
- this(new BufferedReader(new FileReader(TAGS_FILE), 256));
- }
+ public EventLogTags(BufferedReader input) throws IOException {}
- public EventLogTags(BufferedReader input) throws IOException {
- String line;
- while ((line = input.readLine()) != null) {
- Matcher m = COMMENT_PATTERN.matcher(line);
- if (m.matches()) continue;
+ public Description get(String name) { return null; }
- m = TAG_PATTERN.matcher(line);
- if (m.matches()) {
- try {
- int tag = Integer.parseInt(m.group(1));
- Description d = new Description(tag, m.group(2));
- mNameMap.put(d.mName, d);
- mTagMap.put(d.mTag, d);
- } catch (NumberFormatException e) {
- Log.e(TAG, "Error in event log tags entry: " + line, e);
- }
- } else {
- Log.e(TAG, "Can't parse event log tags entry: " + line);
- }
- }
- }
-
- public Description get(String name) {
- return mNameMap.get(name);
- }
-
- public Description get(int tag) {
- return mTagMap.get(tag);
- }
+ public Description get(int tag) { return null; }
}
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index e95d0be..7a959a6 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -81,6 +81,13 @@ public final class Log {
*/
public static final int ASSERT = 7;
+ /**
+ * Exception class used to capture a stack trace in {@link #wtf()}.
+ */
+ private static class TerribleFailure extends Exception {
+ TerribleFailure(String msg, Throwable cause) { super(msg, cause); }
+ }
+
private Log() {
}
@@ -170,24 +177,24 @@ public final class Log {
/**
* Checks to see whether or not a log for the specified tag is loggable at the specified level.
- *
+ *
* The default level of any tag is set to INFO. This means that any level above and including
* INFO will be logged. Before you make any calls to a logging method you should check to see
* if your tag should be logged. You can change the default level by setting a system property:
* 'setprop log.tag.&lt;YOUR_LOG_TAG> &lt;LEVEL>'
- * Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPRESS will
+ * Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
* turn off all logging for your tag. You can also create a local.prop file that with the
* following in it:
* 'log.tag.&lt;YOUR_LOG_TAG>=&lt;LEVEL>'
* and place that in /data/local.prop.
- *
+ *
* @param tag The tag to check.
* @param level The level to check.
* @return Whether or not that this is allowed to be logged.
* @throws IllegalArgumentException is thrown if the tag.length() > 23.
*/
public static native boolean isLoggable(String tag, int level);
-
+
/*
* Send a {@link #WARN} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
@@ -220,6 +227,46 @@ public final class Log {
}
/**
+ * What a Terrible Failure: Report a condition that should never happen.
+ * The error will always be logged at level ASSERT with the call stack.
+ * Depending on system configuration, a report may be added to the
+ * {@link android.os.DropBoxManager} and/or the process may be terminated
+ * immediately with an error dialog.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ * @pending
+ */
+ public static int wtf(String tag, String msg) {
+ return wtf(tag, msg, null);
+ }
+
+ /**
+ * What a Terrible Failure: Report an exception that should never happen.
+ * Similar to {@link #wtf(String, String)}, with an exception to log.
+ * @param tag Used to identify the source of a log message.
+ * @param tr An exception to log.
+ * @pending
+ */
+ public static int wtf(String tag, Throwable tr) {
+ return wtf(tag, tr.getMessage(), tr);
+ }
+
+ /**
+ * What a Terrible Failure: Report an exception that should never happen.
+ * Similar to {@link #wtf(String, Throwable)}, with a message as well.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log. May be null.
+ * @pending
+ */
+ public static int wtf(String tag, String msg, Throwable tr) {
+ tr = new TerribleFailure(msg, tr);
+ int bytes = println(ASSERT, tag, getStackTraceString(tr));
+ RuntimeInit.wtf(tag, tr);
+ return bytes;
+ }
+
+ /**
* Handy function to get a loggable stack trace from a Throwable
* @param tr An exception to log
*/
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 0fc70d5..4f496d7 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -27,7 +27,7 @@ import java.io.IOException;
import java.util.TimeZone;
import java.util.Date;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
/**
* A class containing utility methods related to time zones.
diff --git a/core/java/android/util/XmlPullAttributes.java b/core/java/android/util/XmlPullAttributes.java
index 12d6dd9..8f855cd 100644
--- a/core/java/android/util/XmlPullAttributes.java
+++ b/core/java/android/util/XmlPullAttributes.java
@@ -19,7 +19,7 @@ package android.util;
import org.xmlpull.v1.XmlPullParser;
import android.util.AttributeSet;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
/**
* Provides an implementation of AttributeSet on top of an XmlPullParser.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4176ed1..5bd45a66a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1494,6 +1494,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @hide
*/
static final int OPAQUE_MASK = 0x01800000;
+
+ /**
+ * Indicates a prepressed state;
+ * the short time between ACTION_DOWN and recognizing
+ * a 'real' press. Prepressed is used to recognize quick taps
+ * even when they are shorter than ViewConfiguration.getTapTimeout().
+ *
+ * @hide
+ */
+ private static final int PREPRESSED = 0x02000000;
/**
* The parent this view is attached to.
@@ -1722,6 +1732,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
private int mNextFocusDownId = View.NO_ID;
private CheckForLongPress mPendingCheckForLongPress;
+ private CheckForTap mPendingCheckForTap = null;
+
private UnsetPressedState mUnsetPressedState;
/**
@@ -1762,6 +1774,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* Special tree observer used when mAttachInfo is null.
*/
private ViewTreeObserver mFloatingTreeObserver;
+
+ /**
+ * Cache the touch slop from the context that created the view.
+ */
+ private int mTouchSlop;
// Used for debug only
static long sInstanceCount = 0;
@@ -1777,6 +1794,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
mResources = context != null ? context.getResources() : null;
mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
++sInstanceCount;
+ mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
/**
@@ -3951,7 +3969,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
(event.getRepeatCount() == 0)) {
setPressed(true);
if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
- postCheckForLongClick();
+ postCheckForLongClick(0);
}
return true;
}
@@ -4174,7 +4192,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
- if ((mPrivateFlags & PRESSED) != 0) {
+ boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;
+ if ((mPrivateFlags & PRESSED) != 0 || prepressed) {
// take focus if we don't have it already and we should in
// touch mode.
boolean focusTaken = false;
@@ -4196,24 +4215,31 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
mUnsetPressedState = new UnsetPressedState();
}
- if (!post(mUnsetPressedState)) {
+ if (prepressed) {
+ mPrivateFlags |= PRESSED;
+ refreshDrawableState();
+ postDelayed(mUnsetPressedState,
+ ViewConfiguration.getPressedStateDuration());
+ } else if (!post(mUnsetPressedState)) {
// If the post failed, unpress right now
mUnsetPressedState.run();
}
+ removeTapCallback();
}
break;
case MotionEvent.ACTION_DOWN:
- mPrivateFlags |= PRESSED;
- refreshDrawableState();
- if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
- postCheckForLongClick();
+ if (mPendingCheckForTap == null) {
+ mPendingCheckForTap = new CheckForTap();
}
+ mPrivateFlags |= PREPRESSED;
+ postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
break;
case MotionEvent.ACTION_CANCEL:
mPrivateFlags &= ~PRESSED;
refreshDrawableState();
+ removeTapCallback();
break;
case MotionEvent.ACTION_MOVE:
@@ -4221,25 +4247,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
final int y = (int) event.getY();
// Be lenient about moving outside of buttons
- int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ int slop = mTouchSlop;
if ((x < 0 - slop) || (x >= getWidth() + slop) ||
(y < 0 - slop) || (y >= getHeight() + slop)) {
// Outside button
+ removeTapCallback();
if ((mPrivateFlags & PRESSED) != 0) {
- // Remove any future long press checks
+ // Remove any future long press/tap checks
removeLongPressCallback();
// Need to switch from pressed to not pressed
mPrivateFlags &= ~PRESSED;
refreshDrawableState();
}
- } else {
- // Inside button
- if ((mPrivateFlags & PRESSED) == 0) {
- // Need to switch from not pressed to pressed
- mPrivateFlags |= PRESSED;
- refreshDrawableState();
- }
}
break;
}
@@ -4257,6 +4277,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
removeCallbacks(mPendingCheckForLongPress);
}
}
+
+ /**
+ * Remove the tap detection timer.
+ */
+ private void removeTapCallback() {
+ if (mPendingCheckForTap != null) {
+ mPrivateFlags &= ~PREPRESSED;
+ removeCallbacks(mPendingCheckForTap);
+ }
+ }
/**
* Cancels a pending long press. Your subclass can use this if you
@@ -8427,14 +8457,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
}
- private void postCheckForLongClick() {
+ private void postCheckForLongClick(int delayOffset) {
mHasPerformedLongPress = false;
if (mPendingCheckForLongPress == null) {
mPendingCheckForLongPress = new CheckForLongPress();
}
mPendingCheckForLongPress.rememberWindowAttachCount();
- postDelayed(mPendingCheckForLongPress, ViewConfiguration.getLongPressTimeout());
+ postDelayed(mPendingCheckForLongPress,
+ ViewConfiguration.getLongPressTimeout() - delayOffset);
}
private static int[] stateSetUnion(final int[] stateSet1,
@@ -8611,6 +8642,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
mOriginalWindowAttachCount = mWindowAttachCount;
}
}
+
+ private final class CheckForTap implements Runnable {
+ public void run() {
+ mPrivateFlags &= ~PREPRESSED;
+ mPrivateFlags |= PRESSED;
+ refreshDrawableState();
+ if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
+ postCheckForLongClick(ViewConfiguration.getTapTimeout());
+ }
+ }
+ }
/**
* Interface definition for a callback to be invoked when a key event is
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 993048f..2344c42 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -49,7 +49,7 @@ public class ViewConfiguration {
* Defines the duration in milliseconds of the pressed state in child
* components.
*/
- private static final int PRESSED_STATE_DURATION = 85;
+ private static final int PRESSED_STATE_DURATION = 125;
/**
* Defines the duration in milliseconds before a press turns into
@@ -69,7 +69,7 @@ public class ViewConfiguration {
* is a tap or a scroll. If the user does not move within this interval, it is
* considered to be a tap.
*/
- private static final int TAP_TIMEOUT = 100;
+ private static final int TAP_TIMEOUT = 115;
/**
* Defines the duration in milliseconds we will wait to see if a touch event
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 9232616..3ebe1c2 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -910,7 +910,7 @@ public class ViewDebug {
private static void dump(View root, OutputStream clientStream) throws IOException {
BufferedWriter out = null;
try {
- out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024);
+ out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024);
View view = root.getRootView();
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
diff --git a/core/java/android/view/ViewStub.java b/core/java/android/view/ViewStub.java
index 703a38f..d5e9af4 100644
--- a/core/java/android/view/ViewStub.java
+++ b/core/java/android/view/ViewStub.java
@@ -207,9 +207,11 @@ public final class ViewStub extends View {
} else {
throw new IllegalStateException("setVisibility called on un-referenced view");
}
- } else if (visibility == VISIBLE || visibility == INVISIBLE) {
+ } else {
super.setVisibility(visibility);
- inflate();
+ if (visibility == VISIBLE || visibility == INVISIBLE) {
+ inflate();
+ }
}
}
@@ -244,7 +246,7 @@ public final class ViewStub extends View {
parent.addView(view, index);
}
- mInflatedViewRef = new WeakReference(view);
+ mInflatedViewRef = new WeakReference<View>(view);
if (mInflateListener != null) {
mInflateListener.onInflate(this, view);
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 5d3840a..bbe9c1f 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -662,6 +662,14 @@ public interface WindowManagerPolicy {
public boolean finishAnimationLw();
/**
+ * Return true if it is okay to perform animations for an app transition
+ * that is about to occur. You may return false for this if, for example,
+ * the lock screen is currently displayed so the switch should happen
+ * immediately.
+ */
+ public boolean allowAppAnimationsLw();
+
+ /**
* Called after the screen turns off.
*
* @param why {@link #OFF_BECAUSE_OF_USER} or
@@ -675,6 +683,11 @@ public interface WindowManagerPolicy {
public void screenTurnedOn();
/**
+ * Return whether the screen is currently on.
+ */
+ public boolean isScreenOn();
+
+ /**
* Perform any initial processing of a low-level input event before the
* window manager handles special keys and generates a high-level event
* that is dispatched to the application.
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 13606e7..2aba60b 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -33,13 +33,12 @@ import android.util.Log;
public abstract class WindowOrientationListener {
private static final String TAG = "WindowOrientationListener";
private static final boolean DEBUG = false;
- private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
+ private static final boolean localLOGV = DEBUG || Config.DEBUG;
private SensorManager mSensorManager;
private boolean mEnabled = false;
private int mRate;
private Sensor mSensor;
- private SensorEventListener mSensorEventListener;
- private int mSensorRotation = -1;
+ private SensorEventListenerImpl mSensorEventListener;
/**
* Creates a new WindowOrientationListener.
@@ -80,7 +79,6 @@ public abstract class WindowOrientationListener {
}
if (mEnabled == false) {
if (localLOGV) Log.d(TAG, "WindowOrientationListener enabled");
- mSensorRotation = -1;
mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
mEnabled = true;
}
@@ -96,23 +94,22 @@ public abstract class WindowOrientationListener {
}
if (mEnabled == true) {
if (localLOGV) Log.d(TAG, "WindowOrientationListener disabled");
- mSensorRotation = -1;
mSensorManager.unregisterListener(mSensorEventListener);
mEnabled = false;
}
}
public int getCurrentRotation() {
- return mSensorRotation;
+ if (mEnabled) {
+ return mSensorEventListener.getCurrentRotation();
+ }
+ return -1;
}
class SensorEventListenerImpl implements SensorEventListener {
private static final int _DATA_X = 0;
private static final int _DATA_Y = 1;
private static final int _DATA_Z = 2;
- // Angle around x-axis thats considered almost perfect vertical to hold
- // the device
- private static final int PIVOT = 20;
// Angle around x-asis that's considered almost too vertical. Beyond
// this angle will not result in any orientation changes. f phone faces uses,
// the device is leaning backward.
@@ -121,30 +118,61 @@ public abstract class WindowOrientationListener {
// angle will not result in any orientation changes. If phone faces uses,
// the device is leaning forward.
private static final int PIVOT_LOWER = -10;
- // Upper threshold limit for switching from portrait to landscape
- private static final int PL_UPPER = 295;
- // Lower threshold limit for switching from landscape to portrait
- private static final int LP_LOWER = 320;
- // Lower threshold limt for switching from portrait to landscape
- private static final int PL_LOWER = 270;
- // Upper threshold limit for switching from landscape to portrait
- private static final int LP_UPPER = 359;
- // Minimum angle which is considered landscape
- private static final int LANDSCAPE_LOWER = 235;
- // Minimum angle which is considered portrait
- private static final int PORTRAIT_LOWER = 60;
-
- // Internal value used for calculating linear variant
- private static final float PL_LF_UPPER =
- ((float)(PL_UPPER-PL_LOWER))/((float)(PIVOT_UPPER-PIVOT));
- private static final float PL_LF_LOWER =
- ((float)(PL_UPPER-PL_LOWER))/((float)(PIVOT-PIVOT_LOWER));
- // Internal value used for calculating linear variant
- private static final float LP_LF_UPPER =
- ((float)(LP_UPPER - LP_LOWER))/((float)(PIVOT_UPPER-PIVOT));
- private static final float LP_LF_LOWER =
- ((float)(LP_UPPER - LP_LOWER))/((float)(PIVOT-PIVOT_LOWER));
+ static final int ROTATION_0 = 0;
+ static final int ROTATION_90 = 1;
+ static final int ROTATION_180 = 2;
+ static final int ROTATION_270 = 3;
+ int mRotation = ROTATION_0;
+
+ // Threshold values defined for device rotation positions
+ // follow order ROTATION_0 .. ROTATION_270
+ final int THRESHOLDS[][][] = new int[][][] {
+ {{60, 135}, {135, 225}, {225, 300}},
+ {{0, 45}, {45, 135}, {135, 210}, {330, 360}},
+ {{0, 45}, {45, 120}, {240, 315}, {315, 360}},
+ {{0, 30}, {150, 225}, {225, 315}, {315, 360}}
+ };
+
+ // Transform rotation ranges based on THRESHOLDS. This
+ // has to be in step with THESHOLDS
+ final int ROTATE_TO[][] = new int[][] {
+ {ROTATION_270, ROTATION_180, ROTATION_90},
+ {ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0},
+ {ROTATION_0, ROTATION_270, ROTATION_90, ROTATION_0},
+ {ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0}
+ };
+
+ // Mapping into actual Surface rotation values
+ final int TRANSFORM_ROTATIONS[] = new int[]{Surface.ROTATION_0,
+ Surface.ROTATION_90, Surface.ROTATION_180, Surface.ROTATION_270};
+
+ int getCurrentRotation() {
+ return TRANSFORM_ROTATIONS[mRotation];
+ }
+ private void calculateNewRotation(int orientation, int zyangle) {
+ if (localLOGV) Log.i(TAG, orientation + ", " + zyangle + ", " + mRotation);
+ int rangeArr[][] = THRESHOLDS[mRotation];
+ int row = -1;
+ for (int i = 0; i < rangeArr.length; i++) {
+ if ((orientation >= rangeArr[i][0]) && (orientation < rangeArr[i][1])) {
+ row = i;
+ break;
+ }
+ }
+ if (row != -1) {
+ // Find new rotation based on current rotation value.
+ // This also takes care of irregular rotations as well.
+ int rotation = ROTATE_TO[mRotation][row];
+ if (localLOGV) Log.i(TAG, " new rotation = " + rotation);
+ if (rotation != mRotation) {
+ mRotation = rotation;
+ // Trigger orientation change
+ onOrientationChanged(TRANSFORM_ROTATIONS[rotation]);
+ }
+ }
+ }
+
public void onSensorChanged(SensorEvent event) {
float[] values = event.values;
float X = values[_DATA_X];
@@ -153,53 +181,19 @@ public abstract class WindowOrientationListener {
float OneEightyOverPi = 57.29577957855f;
float gravity = (float) Math.sqrt(X*X+Y*Y+Z*Z);
float zyangle = (float)Math.asin(Z/gravity)*OneEightyOverPi;
- int rotation = -1;
if ((zyangle <= PIVOT_UPPER) && (zyangle >= PIVOT_LOWER)) {
// Check orientation only if the phone is flat enough
// Don't trust the angle if the magnitude is small compared to the y value
float angle = (float)Math.atan2(Y, -X) * OneEightyOverPi;
- int orientation = 90 - (int)Math.round(angle);
+ int orientation = 90 - Math.round(angle);
// normalize to 0 - 359 range
while (orientation >= 360) {
orientation -= 360;
- }
+ }
while (orientation < 0) {
orientation += 360;
}
- // Orientation values between LANDSCAPE_LOWER and PL_LOWER
- // are considered landscape.
- // Ignore orientation values between 0 and LANDSCAPE_LOWER
- // For orientation values between LP_UPPER and PL_LOWER,
- // the threshold gets set linearly around PIVOT.
- if ((orientation >= PL_LOWER) && (orientation <= LP_UPPER)) {
- float threshold;
- float delta = zyangle - PIVOT;
- if (mSensorRotation == Surface.ROTATION_90) {
- if (delta < 0) {
- // Delta is negative
- threshold = LP_LOWER - (LP_LF_LOWER * delta);
- } else {
- threshold = LP_LOWER + (LP_LF_UPPER * delta);
- }
- rotation = (orientation >= threshold) ? Surface.ROTATION_0 : Surface.ROTATION_90;
- } else {
- if (delta < 0) {
- // Delta is negative
- threshold = PL_UPPER+(PL_LF_LOWER * delta);
- } else {
- threshold = PL_UPPER-(PL_LF_UPPER * delta);
- }
- rotation = (orientation <= threshold) ? Surface.ROTATION_90: Surface.ROTATION_0;
- }
- } else if ((orientation >= LANDSCAPE_LOWER) && (orientation < LP_LOWER)) {
- rotation = Surface.ROTATION_90;
- } else if ((orientation >= PL_UPPER) || (orientation <= PORTRAIT_LOWER)) {
- rotation = Surface.ROTATION_0;
- }
- if ((rotation != -1) && (rotation != mSensorRotation)) {
- mSensorRotation = rotation;
- onOrientationChanged(mSensorRotation);
- }
+ calculateNewRotation(orientation, Math.round(zyangle));
}
}
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index b36fa8d..1337bed 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -339,6 +339,7 @@ class BrowserFrame extends Handler {
// loadType is not used yet
if (isMainFrame) {
mCommitted = true;
+ mWebViewCore.getWebView().mViewManager.postResetStateAll();
}
}
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index c4e26bc..22dca3a 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -56,6 +56,9 @@ public final class CacheManager {
private static long CACHE_THRESHOLD = 6 * 1024 * 1024;
private static long CACHE_TRIM_AMOUNT = 2 * 1024 * 1024;
+ // Limit the maximum cache file size to half of the normal capacity
+ static long CACHE_MAX_SIZE = (CACHE_THRESHOLD - CACHE_TRIM_AMOUNT) / 2;
+
private static boolean mDisabled;
// Reference count the enable/disable transaction
@@ -448,7 +451,6 @@ public final class CacheManager {
return;
}
- cacheRet.contentLength = cacheRet.outFile.length();
boolean redirect = checkCacheRedirect(cacheRet.httpStatusCode);
if (redirect) {
// location is in database, no need to keep the file
@@ -470,6 +472,15 @@ public final class CacheManager {
}
}
+ static boolean cleanupCacheFile(CacheResult cacheRet) {
+ try {
+ cacheRet.outStream.close();
+ } catch (IOException e) {
+ return false;
+ }
+ return cacheRet.outFile.delete();
+ }
+
/**
* remove all cache files
*
@@ -644,6 +655,9 @@ public final class CacheManager {
private static CacheResult parseHeaders(int statusCode, Headers headers,
String mimeType) {
+ // if the contentLength is already larger than CACHE_MAX_SIZE, skip it
+ if (headers.getContentLength() > CACHE_MAX_SIZE) return null;
+
// TODO: if authenticated or secure, return null
CacheResult ret = new CacheResult();
ret.httpStatusCode = statusCode;
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 7eb42f2..fb369d3 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -108,8 +108,6 @@ class CallbackProxy extends Handler {
private static final int RECEIVED_TOUCH_ICON_URL = 132;
private static final int GET_VISITED_HISTORY = 133;
private static final int OPEN_FILE_CHOOSER = 134;
- private static final int SHOW_CUSTOM_VIEW = 135;
- private static final int HIDE_CUSTOM_VIEW = 136;
// Message triggered by the client to resume execution
private static final int NOTIFY = 200;
@@ -681,23 +679,6 @@ class CallbackProxy extends Handler {
mWebChromeClient.openFileChooser((UploadFile) msg.obj);
}
break;
-
- case SHOW_CUSTOM_VIEW:
- if (mWebChromeClient != null) {
- HashMap<String, Object> map =
- (HashMap<String, Object>) msg.obj;
- View view = (View) map.get("view");
- WebChromeClient.CustomViewCallback callback =
- (WebChromeClient.CustomViewCallback) map.get("callback");
- mWebChromeClient.onShowCustomView(view, callback);
- }
- break;
-
- case HIDE_CUSTOM_VIEW:
- if (mWebChromeClient != null) {
- mWebChromeClient.onHideCustomView();
- }
- break;
}
}
@@ -1404,24 +1385,4 @@ class CallbackProxy extends Handler {
}
return uploadFile.getResult();
}
-
- /* package */ void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {
- if (mWebChromeClient == null) {
- return;
- }
- Message msg = obtainMessage(SHOW_CUSTOM_VIEW);
- HashMap<String, Object> map = new HashMap<String, Object>();
- map.put("view", view);
- map.put("callback", callback);
- msg.obj = map;
- sendMessage(msg);
- }
-
- /* package */ void hideCustomView() {
- if (mWebChromeClient == null) {
- return;
- }
- Message msg = obtainMessage(HIDE_CUSTOM_VIEW);
- sendMessage(msg);
- }
}
diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java
index 8e25395..dca52f6 100644
--- a/core/java/android/webkit/DebugFlags.java
+++ b/core/java/android/webkit/DebugFlags.java
@@ -32,6 +32,8 @@ class DebugFlags {
public static final boolean CALLBACK_PROXY = false;
public static final boolean COOKIE_MANAGER = false;
public static final boolean COOKIE_SYNC_MANAGER = false;
+ public static final boolean DRAG_TRACKER = false;
+ public static final String DRAG_TRACKER_LOGTAG = "skia";
public static final boolean FRAME_LOADER = false;
public static final boolean J_WEB_CORE_JAVA_BRIDGE = false;// HIGHLY VERBOSE
public static final boolean LOAD_LISTENER = false;
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index c2b9f20..cdc6608 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -936,8 +936,11 @@ class LoadListener extends Handler implements EventHandler {
void downloadFile() {
// Setting the Cache Result to null ensures that this
// content is not added to the cache
- mCacheResult = null;
-
+ if (mCacheResult != null) {
+ CacheManager.cleanupCacheFile(mCacheResult);
+ mCacheResult = null;
+ }
+
// Inform the client that they should download a file
mBrowserFrame.getCallbackProxy().onDownloadStart(url(),
mBrowserFrame.getUserAgentString(),
@@ -1096,10 +1099,18 @@ class LoadListener extends Handler implements EventHandler {
if (c.mLength != 0) {
if (mCacheResult != null) {
- try {
- mCacheResult.outStream.write(c.mArray, 0, c.mLength);
- } catch (IOException e) {
+ mCacheResult.contentLength += c.mLength;
+ if (mCacheResult.contentLength > CacheManager.CACHE_MAX_SIZE) {
+ CacheManager.cleanupCacheFile(mCacheResult);
mCacheResult = null;
+ } else {
+ try {
+ mCacheResult.outStream
+ .write(c.mArray, 0, c.mLength);
+ } catch (IOException e) {
+ CacheManager.cleanupCacheFile(mCacheResult);
+ mCacheResult = null;
+ }
}
}
nativeAddData(c.mArray, c.mLength);
@@ -1117,6 +1128,8 @@ class LoadListener extends Handler implements EventHandler {
if (mCacheResult != null) {
if (getErrorID() == OK) {
CacheManager.saveCacheFile(mUrl, mPostIdentifier, mCacheResult);
+ } else {
+ CacheManager.cleanupCacheFile(mCacheResult);
}
// we need to reset mCacheResult to be null
@@ -1181,7 +1194,10 @@ class LoadListener extends Handler implements EventHandler {
mRequestHandle = null;
}
- mCacheResult = null;
+ if (mCacheResult != null) {
+ CacheManager.cleanupCacheFile(mCacheResult);
+ mCacheResult = null;
+ }
mCancelled = true;
clearNativeLoader();
@@ -1246,6 +1262,8 @@ class LoadListener extends Handler implements EventHandler {
if (getErrorID() == OK) {
CacheManager.saveCacheFile(mUrl, mPostIdentifier,
mCacheResult);
+ } else {
+ CacheManager.cleanupCacheFile(mCacheResult);
}
mCacheResult = null;
}
diff --git a/core/java/android/webkit/PluginFullScreenHolder.java b/core/java/android/webkit/PluginFullScreenHolder.java
new file mode 100644
index 0000000..6a0b145
--- /dev/null
+++ b/core/java/android/webkit/PluginFullScreenHolder.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package android.webkit;
+
+import android.app.Dialog;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+
+class PluginFullScreenHolder extends Dialog {
+
+ private static final String LOGTAG = "FullScreenHolder";
+
+ private final WebView mWebView;
+ private final int mNpp;
+ private int mX;
+ private int mY;
+ private int mWidth;
+ private int mHeight;
+
+ PluginFullScreenHolder(WebView webView, int npp) {
+ super(webView.getContext(), android.R.style.Theme_NoTitleBar_Fullscreen);
+ mWebView = webView;
+ mNpp = npp;
+ }
+
+ Rect getBound() {
+ return new Rect(mX, mY, mWidth, mHeight);
+ }
+
+ /*
+ * x, y, width, height are in the caller's view coordinate system. (x, y) is
+ * relative to the top left corner of the caller's view.
+ */
+ void updateBound(int x, int y, int width, int height) {
+ mX = x;
+ mY = y;
+ mWidth = width;
+ mHeight = height;
+ }
+
+ @Override
+ public void onBackPressed() {
+ mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN)
+ .sendToTarget();
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (event.isSystem()) {
+ return super.onKeyDown(keyCode, event);
+ }
+ mWebView.onKeyDown(keyCode, event);
+ // always return true as we are the handler
+ return true;
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (event.isSystem()) {
+ return super.onKeyUp(keyCode, event);
+ }
+ mWebView.onKeyUp(keyCode, event);
+ // always return true as we are the handler
+ return true;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ final float x = event.getX();
+ final float y = event.getY();
+ // TODO: find a way to know when the dialog size changed so that we can
+ // cache the ratio
+ final View decorView = getWindow().getDecorView();
+ event.setLocation(mX + x * mWidth / decorView.getWidth(),
+ mY + y * mHeight / decorView.getHeight());
+ mWebView.onTouchEvent(event);
+ // always return true as we are the handler
+ return true;
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ mWebView.onTrackballEvent(event);
+ // always return true as we are the handler
+ return true;
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mWebView.getWebViewCore().sendMessage(
+ WebViewCore.EventHub.HIDE_FULLSCREEN, mNpp, 0);
+ }
+
+}
diff --git a/core/java/android/webkit/ViewManager.java b/core/java/android/webkit/ViewManager.java
index 6a838c3..75db0a0 100644
--- a/core/java/android/webkit/ViewManager.java
+++ b/core/java/android/webkit/ViewManager.java
@@ -16,7 +16,6 @@
package android.webkit;
-import android.content.Context;
import android.view.View;
import android.widget.AbsoluteLayout;
@@ -26,6 +25,7 @@ class ViewManager {
private final WebView mWebView;
private final ArrayList<ChildView> mChildren = new ArrayList<ChildView>();
private boolean mHidden;
+ private boolean mReadyToDraw;
class ChildView {
int x;
@@ -70,6 +70,9 @@ class ViewManager {
void attachViewOnUIThread(AbsoluteLayout.LayoutParams lp) {
mWebView.addView(mView, lp);
mChildren.add(this);
+ if (!mReadyToDraw) {
+ mView.setVisibility(View.GONE);
+ }
}
void removeView() {
@@ -154,4 +157,23 @@ class ViewManager {
}
mHidden = false;
}
+
+ void postResetStateAll() {
+ mWebView.mPrivateHandler.post(new Runnable() {
+ public void run() {
+ mReadyToDraw = false;
+ }
+ });
+ }
+
+ void postReadyToDrawAll() {
+ mWebView.mPrivateHandler.post(new Runnable() {
+ public void run() {
+ mReadyToDraw = true;
+ for (ChildView v : mChildren) {
+ v.mView.setVisibility(View.VISIBLE);
+ }
+ }
+ });
+ }
}
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 92da456..b6891b1 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -84,12 +84,6 @@ import java.util.ArrayList;
// True if the most recent drag event has caused either the TextView to
// scroll or the web page to scroll. Gets reset after a touch down.
private boolean mScrolled;
- // Gets set to true any time the WebTextView has focus, but the navigation
- // cache does not yet know that the focus has been changed. This happens
- // if the user presses "Next", if the user moves the cursor to a textfield
- // and starts typing or clicks the trackball/center key, and when the user
- // touches a textfield.
- boolean mOkayForFocusNotToMatch;
// Whether or not a selection change was generated from webkit. If it was,
// we do not need to pass the selection back to webkit.
private boolean mFromWebKit;
@@ -151,22 +145,6 @@ import java.util.ArrayList;
break;
}
- if (down) {
- if (mOkayForFocusNotToMatch) {
- if (mWebView.nativeFocusNodePointer() == mNodePointer) {
- mOkayForFocusNotToMatch = false;
- }
- } else if (mWebView.nativeFocusNodePointer() != mNodePointer
- && !isArrowKey) {
- mWebView.nativeClearCursor();
- // Do not call remove() here, which hides the soft keyboard. If
- // the soft keyboard is being displayed, the user will still want
- // it there.
- mWebView.removeView(this);
- mWebView.requestFocus();
- return mWebView.dispatchKeyEvent(event);
- }
- }
Spannable text = (Spannable) getText();
int oldLength = text.length();
// Normally the delete key's dom events are sent via onTextChanged.
@@ -324,7 +302,6 @@ import java.util.ArrayList;
// focus, set the focus controller back to inactive
mWebView.setFocusControllerInactive();
mWebView.nativeMoveCursorToNextTextInput();
- mOkayForFocusNotToMatch = true;
// Preemptively rebuild the WebTextView, so that the action will
// be set properly.
mWebView.rebuildWebTextView();
@@ -865,7 +842,10 @@ import java.util.ArrayList;
default:
break;
}
+ setHint(null);
if (single) {
+ mWebView.requestLabel(mWebView.nativeFocusCandidateFramePointer(),
+ mNodePointer);
maxLength = mWebView.nativeFocusCandidateMaxLength();
if (type != 2 /* PASSWORD */) {
String name = mWebView.nativeFocusCandidateName();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7d49cb6..a6a48cb 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -25,6 +25,7 @@ import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.Picture;
import android.graphics.Point;
import android.graphics.Rect;
@@ -207,6 +208,9 @@ public class WebView extends AbsoluteLayout
static private final boolean AUTO_REDRAW_HACK = false;
// true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK
private boolean mAutoRedraw;
+ private int mRootLayer; // C++ pointer to the root layer
+ private boolean mLayersHaveAnimations;
+ private EvaluateLayersAnimations mEvaluateThread;
static final String LOGTAG = "webview";
@@ -301,6 +305,9 @@ public class WebView extends AbsoluteLayout
// Used by WebViewCore to create child views.
/* package */ final ViewManager mViewManager;
+ // Used to display in full screen mode
+ PluginFullScreenHolder mFullScreenHolder;
+
/**
* Position of the last touch event.
*/
@@ -479,7 +486,7 @@ public class WebView extends AbsoluteLayout
static final int MOVE_OUT_OF_PLUGIN = 19;
static final int CLEAR_TEXT_ENTRY = 20;
static final int UPDATE_TEXT_SELECTION_MSG_ID = 21;
- static final int UPDATE_CLIPBOARD = 22;
+
static final int LONG_PRESS_CENTER = 23;
static final int PREVENT_TOUCH_ID = 24;
static final int WEBCORE_NEED_TOUCH_EVENTS = 25;
@@ -487,6 +494,12 @@ public class WebView extends AbsoluteLayout
static final int INVAL_RECT_MSG_ID = 26;
static final int REQUEST_KEYBOARD = 27;
static final int DO_MOTION_UP = 28;
+ static final int SHOW_FULLSCREEN = 29;
+ static final int HIDE_FULLSCREEN = 30;
+ static final int DOM_FOCUS_CHANGED = 31;
+ static final int IMMEDIATE_REPAINT_MSG_ID = 32;
+ static final int SET_ROOT_LAYER_MSG_ID = 33;
+ static final int RETURN_LABEL = 34;
static final String[] HandlerDebugString = {
"REMEMBER_PASSWORD", // = 1;
@@ -510,13 +523,19 @@ public class WebView extends AbsoluteLayout
"MOVE_OUT_OF_PLUGIN", // = 19;
"CLEAR_TEXT_ENTRY", // = 20;
"UPDATE_TEXT_SELECTION_MSG_ID", // = 21;
- "UPDATE_CLIPBOARD", // = 22;
+ "22", // = 22;
"LONG_PRESS_CENTER", // = 23;
"PREVENT_TOUCH_ID", // = 24;
"WEBCORE_NEED_TOUCH_EVENTS", // = 25;
"INVAL_RECT_MSG_ID", // = 26;
"REQUEST_KEYBOARD", // = 27;
- "DO_MOTION_UP" // = 28;
+ "DO_MOTION_UP", // = 28;
+ "SHOW_FULLSCREEN", // = 29;
+ "HIDE_FULLSCREEN", // = 30;
+ "DOM_FOCUS_CHANGED", // = 31;
+ "IMMEDIATE_REPAINT_MSG_ID", // = 32;
+ "SET_ROOT_LAYER_MSG_ID", // = 33;
+ "RETURN_LABEL" // = 34;
};
// If the site doesn't use the viewport meta tag to specify the viewport,
@@ -765,12 +784,11 @@ public class WebView extends AbsoluteLayout
init();
mCallbackProxy = new CallbackProxy(context, this);
+ mViewManager = new ViewManager(this);
mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javascriptInterfaces);
mDatabase = WebViewDatabase.getInstance(context);
mScroller = new Scroller(context);
- mViewManager = new ViewManager(this);
-
mZoomButtonsController = new ZoomButtonsController(this);
mZoomButtonsController.setOnZoomListener(mZoomListener);
// ZoomButtonsController positions the buttons at the bottom, but in
@@ -1719,6 +1737,13 @@ public class WebView extends AbsoluteLayout
return result;
}
+ // Called by JNI when the DOM has changed the focus. Clear the focus so
+ // that new keys will go to the newly focused field
+ private void domChangedFocus() {
+ if (inEditingMode()) {
+ mPrivateHandler.obtainMessage(DOM_FOCUS_CHANGED).sendToTarget();
+ }
+ }
/**
* Request the href of an anchor element due to getFocusNodePath returning
* "href." If hrefMsg is null, this method returns immediately and does not
@@ -2860,16 +2885,7 @@ public class WebView extends AbsoluteLayout
return super.drawChild(canvas, child, drawingTime);
}
- @Override
- protected void onDraw(Canvas canvas) {
- // if mNativeClass is 0, the WebView has been destroyed. Do nothing.
- if (mNativeClass == 0) {
- return;
- }
- int saveCount = canvas.save();
- if (mTitleBar != null) {
- canvas.translate(0, (int) mTitleBar.getHeight());
- }
+ private void drawContent(Canvas canvas) {
// Update the buttons in the picture, so when we draw the picture
// to the screen, they are in the correct state.
// Tell the native side if user is a) touching the screen,
@@ -2879,9 +2895,25 @@ public class WebView extends AbsoluteLayout
// If mNativeClass is 0, we should not reach here, so we do not
// need to check it again.
nativeRecordButtons(hasFocus() && hasWindowFocus(),
- mTouchMode == TOUCH_SHORTPRESS_START_MODE
- || mTrackballDown || mGotCenterDown, false);
+ mTouchMode == TOUCH_SHORTPRESS_START_MODE
+ || mTrackballDown || mGotCenterDown, false);
drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ // if mNativeClass is 0, the WebView has been destroyed. Do nothing.
+ if (mNativeClass == 0) {
+ return;
+ }
+
+ int saveCount = canvas.save();
+ if (mTitleBar != null) {
+ canvas.translate(0, (int) mTitleBar.getHeight());
+ }
+ if (mDragTrackerHandler == null || !mDragTrackerHandler.draw(canvas)) {
+ drawContent(canvas);
+ }
canvas.restoreToCount(saveCount);
// Now draw the shadow.
@@ -2896,6 +2928,7 @@ public class WebView extends AbsoluteLayout
if (AUTO_REDRAW_HACK && mAutoRedraw) {
invalidate();
}
+ mWebViewCore.signalRepaintDone();
}
@Override
@@ -2963,11 +2996,20 @@ public class WebView extends AbsoluteLayout
}
}
+ private void drawLayers(Canvas canvas) {
+ if (mRootLayer != 0) {
+ float scrollY = Math.max(mScrollY - getTitleHeight(), 0);
+ nativeDrawLayers(mRootLayer, mScrollX, scrollY,
+ mActualScale, canvas);
+ }
+ }
+
private void drawCoreAndCursorRing(Canvas canvas, int color,
boolean drawCursorRing) {
if (mDrawHistory) {
canvas.scale(mActualScale, mActualScale);
canvas.drawPicture(mHistoryPicture);
+ drawLayers(canvas);
return;
}
@@ -3046,6 +3088,8 @@ public class WebView extends AbsoluteLayout
mWebViewCore.drawContentPicture(canvas, color, animateZoom,
animateScroll);
+ drawLayers(canvas);
+
if (mNativeClass == 0) return;
if (mShiftIsPressed && !animateZoom) {
if (mTouchSelection || mExtendSelection) {
@@ -3177,16 +3221,6 @@ public class WebView extends AbsoluteLayout
imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
}
- /**
- * Only for calling from JNI. Allows a click on an unfocused textfield to
- * put the textfield in focus.
- */
- private void setOkayNotToMatch() {
- if (inEditingMode()) {
- mWebTextView.mOkayForFocusNotToMatch = true;
- }
- }
-
/*
* This method checks the current focus and cursor and potentially rebuilds
* mWebTextView to have the appropriate properties, such as password,
@@ -3276,6 +3310,51 @@ public class WebView extends AbsoluteLayout
}
}
+ /**
+ * Pass a message to find out the <label> associated with the <input>
+ * identified by nodePointer
+ * @param framePointer Pointer to the frame containing the <input> node
+ * @param nodePointer Pointer to the node for which a <label> is desired.
+ */
+ /* package */ void requestLabel(int framePointer, int nodePointer) {
+ mWebViewCore.sendMessage(EventHub.REQUEST_LABEL, framePointer,
+ nodePointer);
+ }
+
+ /*
+ * This class runs the layers animations in their own thread,
+ * so that we do not slow down the UI.
+ */
+ private class EvaluateLayersAnimations extends Thread {
+ boolean mRunning = true;
+ // delay corresponds to 40fps, no need to go faster.
+ int mDelay = 25; // in ms
+ public void run() {
+ while (mRunning) {
+ if (mLayersHaveAnimations && mRootLayer != 0) {
+ // updates is a C++ pointer to a Vector of AnimationValues
+ int updates = nativeEvaluateLayersAnimations(mRootLayer);
+ if (updates == 0) {
+ mRunning = false;
+ }
+ Message.obtain(mPrivateHandler,
+ WebView.IMMEDIATE_REPAINT_MSG_ID,
+ updates, 0).sendToTarget();
+ } else {
+ mRunning = false;
+ }
+ try {
+ Thread.currentThread().sleep(mDelay);
+ } catch (InterruptedException e) {
+ mRunning = false;
+ }
+ }
+ }
+ public void cancel() {
+ mRunning = false;
+ }
+ }
+
/*
* This class requests an Adapter for the WebTextView which shows past
* entries stored in the database. It is a Runnable so that it can be done
@@ -3448,7 +3527,6 @@ public class WebView extends AbsoluteLayout
// Now we need to pass the event to it
if (inEditingMode()) {
mWebTextView.setDefaultSelection();
- mWebTextView.mOkayForFocusNotToMatch = true;
return mWebTextView.dispatchKeyEvent(event);
}
} else if (nativeHasFocusNode()) {
@@ -3545,7 +3623,6 @@ public class WebView extends AbsoluteLayout
centerKeyPressOnTextField();
if (inEditingMode()) {
mWebTextView.setDefaultSelection();
- mWebTextView.mOkayForFocusNotToMatch = true;
}
return true;
}
@@ -3597,14 +3674,22 @@ public class WebView extends AbsoluteLayout
private boolean commitCopy() {
boolean copiedSomething = false;
if (mExtendSelection) {
- // copy region so core operates on copy without touching orig.
- Region selection = new Region(nativeGetSelection());
- if (selection.isEmpty() == false) {
+ String selection = nativeGetSelection();
+ if (selection != "") {
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "commitCopy \"" + selection + "\"");
+ }
Toast.makeText(mContext
, com.android.internal.R.string.text_copied
, Toast.LENGTH_SHORT).show();
- mWebViewCore.sendMessage(EventHub.GET_SELECTION, selection);
copiedSomething = true;
+ try {
+ IClipboard clip = IClipboard.Stub.asInterface(
+ ServiceManager.getService("clipboard"));
+ clip.setClipboardText(selection);
+ } catch (android.os.RemoteException e) {
+ Log.e(LOGTAG, "Clipboard failed", e);
+ }
}
mExtendSelection = false;
}
@@ -3858,6 +3943,166 @@ public class WebView extends AbsoluteLayout
private static final float MAX_SLOPE_FOR_DIAG = 1.5f;
private static final int MIN_BREAK_SNAP_CROSS_DISTANCE = 80;
+ private static int sign(float x) {
+ return x > 0 ? 1 : (x < 0 ? -1 : 0);
+ }
+
+ // if the page can scroll <= this value, we won't allow the drag tracker
+ // to have any effect.
+ private static final int MIN_SCROLL_AMOUNT_TO_DISABLE_DRAG_TRACKER = 4;
+
+ private class DragTrackerHandler {
+ private final DragTracker mProxy;
+ private final float mStartY, mStartX;
+ private final float mMinDY, mMinDX;
+ private final float mMaxDY, mMaxDX;
+ private float mCurrStretchY, mCurrStretchX;
+ private int mSX, mSY;
+
+ public DragTrackerHandler(float x, float y, DragTracker proxy) {
+ mProxy = proxy;
+
+ int docBottom = computeVerticalScrollRange() + getTitleHeight();
+ int viewTop = getScrollY();
+ int viewBottom = viewTop + getHeight();
+
+ mStartY = y;
+ mMinDY = -viewTop;
+ mMaxDY = docBottom - viewBottom;
+
+ if (DebugFlags.DRAG_TRACKER) {
+ Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, " dragtracker y= " + y +
+ " up/down= " + mMinDY + " " + mMaxDY);
+ }
+
+ int docRight = computeHorizontalScrollRange();
+ int viewLeft = getScrollX();
+ int viewRight = viewLeft + getWidth();
+ mStartX = x;
+ mMinDX = -viewLeft;
+ mMaxDX = docRight - viewRight;
+
+ mProxy.onStartDrag(x, y);
+
+ // ensure we buildBitmap at least once
+ mSX = -99999;
+ }
+
+ private float computeStretch(float delta, float min, float max) {
+ float stretch = 0;
+ if (max - min > MIN_SCROLL_AMOUNT_TO_DISABLE_DRAG_TRACKER) {
+ if (delta < min) {
+ stretch = delta - min;
+ } else if (delta > max) {
+ stretch = delta - max;
+ }
+ }
+ return stretch;
+ }
+
+ public void dragTo(float x, float y) {
+ float sy = computeStretch(mStartY - y, mMinDY, mMaxDY);
+ float sx = computeStretch(mStartX - x, mMinDX, mMaxDX);
+
+ if (mCurrStretchX != sx || mCurrStretchY != sy) {
+ mCurrStretchX = sx;
+ mCurrStretchY = sy;
+ if (DebugFlags.DRAG_TRACKER) {
+ Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, "---- stretch " + sx +
+ " " + sy);
+ }
+ if (mProxy.onStretchChange(sx, sy)) {
+ invalidate();
+ }
+ }
+ }
+
+ public void stopDrag() {
+ if (DebugFlags.DRAG_TRACKER) {
+ Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, "----- stopDrag");
+ }
+ mProxy.onStopDrag();
+ }
+
+ private int hiddenHeightOfTitleBar() {
+ return getTitleHeight() - getVisibleTitleHeight();
+ }
+
+ // need a way to know if 565 or 8888 is the right config for
+ // capturing the display and giving it to the drag proxy
+ private Bitmap.Config offscreenBitmapConfig() {
+ // hard code 565 for now
+ return Bitmap.Config.RGB_565;
+ }
+
+ /* If the tracker draws, then this returns true, otherwise it will
+ return false, and draw nothing.
+ */
+ public boolean draw(Canvas canvas) {
+ if (mCurrStretchX != 0 || mCurrStretchY != 0) {
+ int sx = getScrollX();
+ int sy = getScrollY() - hiddenHeightOfTitleBar();
+
+ if (mSX != sx || mSY != sy) {
+ buildBitmap(sx, sy);
+ mSX = sx;
+ mSY = sy;
+ }
+
+ int count = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ canvas.translate(sx, sy);
+ mProxy.onDraw(canvas);
+ canvas.restoreToCount(count);
+ return true;
+ }
+ if (DebugFlags.DRAG_TRACKER) {
+ Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, " -- draw false " +
+ mCurrStretchX + " " + mCurrStretchY);
+ }
+ return false;
+ }
+
+ private void buildBitmap(int sx, int sy) {
+ int w = getWidth();
+ int h = getViewHeight();
+ Bitmap bm = Bitmap.createBitmap(w, h, offscreenBitmapConfig());
+ Canvas canvas = new Canvas(bm);
+ canvas.translate(-sx, -sy);
+ drawContent(canvas);
+
+ if (DebugFlags.DRAG_TRACKER) {
+ Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, "--- buildBitmap " + sx +
+ " " + sy + " " + w + " " + h);
+ }
+ mProxy.onBitmapChange(bm);
+ }
+ }
+
+ /** @hide */
+ public static class DragTracker {
+ public void onStartDrag(float x, float y) {}
+ public boolean onStretchChange(float sx, float sy) {
+ // return true to have us inval the view
+ return false;
+ }
+ public void onStopDrag() {}
+ public void onBitmapChange(Bitmap bm) {}
+ public void onDraw(Canvas canvas) {}
+ }
+
+ /** @hide */
+ public DragTracker getDragTracker() {
+ return mDragTracker;
+ }
+
+ /** @hide */
+ public void setDragTracker(DragTracker tracker) {
+ mDragTracker = tracker;
+ }
+
+ private DragTracker mDragTracker;
+ private DragTrackerHandler mDragTrackerHandler;
+
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mNativeClass == 0 || !isClickable() || !isLongClickable()) {
@@ -3956,6 +4201,10 @@ public class WebView extends AbsoluteLayout
mLastTouchTime = eventTime;
mVelocityTracker = VelocityTracker.obtain();
mSnapScrollMode = SNAP_NONE;
+ if (mDragTracker != null) {
+ mDragTrackerHandler = new DragTrackerHandler(x, y,
+ mDragTracker);
+ }
break;
}
case MotionEvent.ACTION_MOVE: {
@@ -3993,6 +4242,11 @@ public class WebView extends AbsoluteLayout
|| mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
}
+ if (mFullScreenHolder != null) {
+ // in full screen mode, the WebView can't be panned.
+ mTouchMode = TOUCH_DONE_MODE;
+ break;
+ }
// if it starts nearly horizontal or vertical, enforce it
int ax = Math.abs(deltaX);
@@ -4120,6 +4374,10 @@ public class WebView extends AbsoluteLayout
}
}
+ if (mDragTrackerHandler != null) {
+ mDragTrackerHandler.dragTo(x, y);
+ }
+
if (keepScrollBarsVisible) {
if (mHeldMotionless != MOTIONLESS_TRUE) {
mHeldMotionless = MOTIONLESS_TRUE;
@@ -4135,6 +4393,10 @@ public class WebView extends AbsoluteLayout
break;
}
case MotionEvent.ACTION_UP: {
+ if (mDragTrackerHandler != null) {
+ mDragTrackerHandler.stopDrag();
+ mDragTrackerHandler = null;
+ }
mLastTouchUpTime = eventTime;
switch (mTouchMode) {
case TOUCH_DOUBLE_TAP_MODE: // double tap
@@ -4147,7 +4409,7 @@ public class WebView extends AbsoluteLayout
ted.mX = viewToContentX((int) x + mScrollX);
ted.mY = viewToContentY((int) y + mScrollY);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
- } else {
+ } else if (mFullScreenHolder == null) {
doDoubleTap();
}
break;
@@ -4163,8 +4425,9 @@ public class WebView extends AbsoluteLayout
if ((deltaX * deltaX + deltaY * deltaY) > mTouchSlopSquare) {
Log.w(LOGTAG, "Miss a drag as we are waiting for" +
" WebCore's response for touch down.");
- if (computeHorizontalScrollExtent() < computeHorizontalScrollRange()
- || computeVerticalScrollExtent() < computeVerticalScrollRange()) {
+ if (mFullScreenHolder == null
+ && (computeHorizontalScrollExtent() < computeHorizontalScrollRange()
+ || computeVerticalScrollExtent() < computeVerticalScrollRange())) {
// we will not rewrite drag code here, but we
// will try fling if it applies.
WebViewCore.pauseUpdate(mWebViewCore);
@@ -4224,6 +4487,10 @@ public class WebView extends AbsoluteLayout
break;
}
case MotionEvent.ACTION_CANCEL: {
+ if (mDragTrackerHandler != null) {
+ mDragTrackerHandler.stopDrag();
+ mDragTrackerHandler = null;
+ }
// we also use mVelocityTracker == null to tell us that we are
// not "moving around", so we can take the slower/prettier
// mode in the drawing code
@@ -5115,7 +5382,7 @@ public class WebView extends AbsoluteLayout
// exclude INVAL_RECT_MSG_ID since it is frequently output
if (DebugFlags.WEB_VIEW && msg.what != INVAL_RECT_MSG_ID) {
Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what
- > DO_MOTION_UP ? Integer.toString(msg.what)
+ > RETURN_LABEL ? Integer.toString(msg.what)
: HandlerDebugString[msg.what - REMEMBER_PASSWORD]);
}
if (mWebViewCore == null) {
@@ -5146,7 +5413,9 @@ public class WebView extends AbsoluteLayout
mPreventDoubleTap = false;
}
if (mTouchMode == TOUCH_INIT_MODE) {
- mTouchMode = TOUCH_SHORTPRESS_START_MODE;
+ mTouchMode = mFullScreenHolder == null
+ ? TOUCH_SHORTPRESS_START_MODE
+ : TOUCH_SHORTPRESS_MODE;
updateSelection();
} else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mTouchMode = TOUCH_DONE_MODE;
@@ -5164,8 +5433,10 @@ public class WebView extends AbsoluteLayout
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDrag == PREVENT_DRAG_NO) {
mTouchMode = TOUCH_DONE_MODE;
- performLongClick();
- rebuildWebTextView();
+ if (mFullScreenHolder == null) {
+ performLongClick();
+ rebuildWebTextView();
+ }
}
break;
}
@@ -5209,7 +5480,8 @@ public class WebView extends AbsoluteLayout
final Point viewSize = draw.mViewPoint;
boolean useWideViewport = settings.getUseWideViewPort();
WebViewCore.RestoreState restoreState = draw.mRestoreState;
- if (restoreState != null) {
+ boolean hasRestoreState = restoreState != null;
+ if (hasRestoreState) {
mInZoomOverview = false;
mLastScale = mInitialScaleInPercent > 0
? mInitialScaleInPercent / 100.0f
@@ -5299,6 +5571,9 @@ public class WebView extends AbsoluteLayout
if (draw.mFocusSizeChanged && inEditingMode()) {
mFocusSizeChanged = true;
}
+ if (hasRestoreState) {
+ mViewManager.postReadyToDrawAll();
+ }
break;
}
case WEBCORE_INITIALIZED_MSG_ID:
@@ -5338,6 +5613,20 @@ public class WebView extends AbsoluteLayout
tData.mEnd);
}
break;
+ case RETURN_LABEL:
+ if (inEditingMode()
+ && mWebTextView.isSameTextField(msg.arg1)) {
+ mWebTextView.setHint((String) msg.obj);
+ InputMethodManager imm
+ = InputMethodManager.peekInstance();
+ // The hint is propagated to the IME in
+ // onCreateInputConnection. If the IME is already
+ // active, restart it so that its hint text is updated.
+ if (imm != null && imm.isActive(mWebTextView)) {
+ imm.restartInput(mWebTextView);
+ }
+ }
+ break;
case MOVE_OUT_OF_PLUGIN:
navHandledKey(msg.arg1, 1, false, 0, true);
break;
@@ -5363,25 +5652,44 @@ public class WebView extends AbsoluteLayout
}
break;
}
+ case IMMEDIATE_REPAINT_MSG_ID: {
+ int updates = msg.arg1;
+ if (updates != 0) {
+ // updates is a C++ pointer to a Vector of
+ // AnimationValues that we apply to the layers.
+ // The Vector is deallocated in nativeUpdateLayers().
+ nativeUpdateLayers(mRootLayer, updates);
+ }
+ invalidate();
+ break;
+ }
+ case SET_ROOT_LAYER_MSG_ID: {
+ int oldLayer = mRootLayer;
+ mRootLayer = msg.arg1;
+ if (oldLayer > 0) {
+ nativeDestroyLayer(oldLayer);
+ }
+ if (mRootLayer == 0) {
+ mLayersHaveAnimations = false;
+ }
+ if (mEvaluateThread != null) {
+ mEvaluateThread.cancel();
+ mEvaluateThread = null;
+ }
+ if (nativeLayersHaveAnimations(mRootLayer)) {
+ mLayersHaveAnimations = true;
+ mEvaluateThread = new EvaluateLayersAnimations();
+ mEvaluateThread.start();
+ }
+ invalidate();
+ break;
+ }
case REQUEST_FORM_DATA:
AutoCompleteAdapter adapter = (AutoCompleteAdapter) msg.obj;
if (mWebTextView.isSameTextField(msg.arg1)) {
mWebTextView.setAdapterCustom(adapter);
}
break;
- case UPDATE_CLIPBOARD:
- String str = (String) msg.obj;
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "UPDATE_CLIPBOARD " + str);
- }
- try {
- IClipboard clip = IClipboard.Stub.asInterface(
- ServiceManager.getService("clipboard"));
- clip.setClipboardText(str);
- } catch (android.os.RemoteException e) {
- Log.e(LOGTAG, "Clipboard failed", e);
- }
- break;
case RESUME_WEBCORE_UPDATE:
WebViewCore.resumeUpdate(mWebViewCore);
break;
@@ -5466,6 +5774,79 @@ public class WebView extends AbsoluteLayout
doMotionUp(msg.arg1, msg.arg2, (Boolean) msg.obj);
break;
+ case SHOW_FULLSCREEN:
+ WebViewCore.PluginFullScreenData data
+ = (WebViewCore.PluginFullScreenData) msg.obj;
+ if (data.mNpp != 0 && data.mView != null) {
+ if (mFullScreenHolder != null) {
+ Log.w(LOGTAG,
+ "Should not have another full screen.");
+ mFullScreenHolder.dismiss();
+ }
+ mFullScreenHolder = new PluginFullScreenHolder(
+ WebView.this, data.mNpp);
+ mFullScreenHolder.setContentView(data.mView);
+ mFullScreenHolder.setCancelable(false);
+ mFullScreenHolder.setCanceledOnTouchOutside(false);
+ mFullScreenHolder.show();
+ }
+ // move the matching embedded view fully into the view so
+ // that touch will be valid instead of rejected due to out
+ // of the visible bounds
+ // TODO: do we need to preserve the original position and
+ // scale so that we can revert it when leaving the full
+ // screen mode?
+ int x = contentToViewX(data.mDocX);
+ int y = contentToViewY(data.mDocY);
+ int width = contentToViewDimension(data.mDocWidth);
+ int height = contentToViewDimension(data.mDocHeight);
+ int viewWidth = getViewWidth();
+ int viewHeight = getViewHeight();
+ int newX = mScrollX;
+ int newY = mScrollY;
+ if (x < mScrollX) {
+ newX = x + (width > viewWidth
+ ? (width - viewWidth) / 2 : 0);
+ } else if (x + width > mScrollX + viewWidth) {
+ newX = x + width - viewWidth - (width > viewWidth
+ ? (width - viewWidth) / 2 : 0);
+ }
+ if (y < mScrollY) {
+ newY = y + (height > viewHeight
+ ? (height - viewHeight) / 2 : 0);
+ } else if (y + height > mScrollY + viewHeight) {
+ newY = y + height - viewHeight - (height > viewHeight
+ ? (height - viewHeight) / 2 : 0);
+ }
+ scrollTo(newX, newY);
+ if (width > viewWidth || height > viewHeight) {
+ mZoomCenterX = viewWidth * .5f;
+ mZoomCenterY = viewHeight * .5f;
+ setNewZoomScale(mActualScale
+ / Math.max((float) width / viewWidth,
+ (float) height / viewHeight), false);
+ }
+ // Now update the bound
+ mFullScreenHolder.updateBound(contentToViewX(data.mDocX)
+ - mScrollX, contentToViewY(data.mDocY) - mScrollY,
+ contentToViewDimension(data.mDocWidth),
+ contentToViewDimension(data.mDocHeight));
+ break;
+
+ case HIDE_FULLSCREEN:
+ if (mFullScreenHolder != null) {
+ mFullScreenHolder.dismiss();
+ mFullScreenHolder = null;
+ }
+ break;
+
+ case DOM_FOCUS_CHANGED:
+ if (inEditingMode()) {
+ nativeClearCursor();
+ rebuildWebTextView();
+ }
+ break;
+
default:
super.handleMessage(msg);
break;
@@ -5977,6 +6358,13 @@ public class WebView extends AbsoluteLayout
private native void nativeDebugDump();
private native void nativeDestroy();
private native void nativeDrawCursorRing(Canvas content);
+ private native void nativeDestroyLayer(int layer);
+ private native int nativeEvaluateLayersAnimations(int layer);
+ private native boolean nativeLayersHaveAnimations(int layer);
+ private native void nativeUpdateLayers(int layer, int updates);
+ private native void nativeDrawLayers(int layer,
+ float scrollX, float scrollY,
+ float scale, Canvas canvas);
private native void nativeDrawMatches(Canvas canvas);
private native void nativeDrawSelectionPointer(Canvas content,
float scale, int x, int y, boolean extendSelection);
@@ -5984,7 +6372,7 @@ public class WebView extends AbsoluteLayout
private native void nativeDumpDisplayTree(String urlOrNull);
private native int nativeFindAll(String findLower, String findUpper);
private native void nativeFindNext(boolean forward);
- private native int nativeFocusCandidateFramePointer();
+ /* package */ native int nativeFocusCandidateFramePointer();
private native boolean nativeFocusCandidateIsPassword();
private native boolean nativeFocusCandidateIsPlugin();
private native boolean nativeFocusCandidateIsRtlText();
@@ -6003,7 +6391,7 @@ public class WebView extends AbsoluteLayout
private native boolean nativeFocusIsPlugin();
/* package */ native int nativeFocusNodePointer();
private native Rect nativeGetCursorRingBounds();
- private native Region nativeGetSelection();
+ private native String nativeGetSelection();
private native boolean nativeHasCursorNode();
private native boolean nativeHasFocusNode();
private native void nativeHideCursor();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index e198ee8..724493b 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -41,7 +41,6 @@ import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
-import android.webkit.plugin.FullScreenDrawingModel;
import android.webkit.plugin.SurfaceDrawingModel;
import android.webkit.plugin.WebkitPlugin;
@@ -548,8 +547,6 @@ final class WebViewCore {
*/
private native void nativeSetSelection(int start, int end);
- private native String nativeGetSelection(Region sel);
-
// Register a scheme to be treated as local scheme so that it can access
// local asset files for resources
private native void nativeRegisterURLSchemeAsLocal(String scheme);
@@ -737,7 +734,17 @@ final class WebViewCore {
boolean mRemember;
}
+ static class PluginFullScreenData {
+ View mView;
+ int mNpp;
+ int mDocX;
+ int mDocY;
+ int mDocWidth;
+ int mDocHeight;
+ }
+
static final String[] HandlerDebugString = {
+ "REQUEST_LABEL", // 97
"UPDATE_FRAME_CACHE_IF_LOADING", // = 98
"SCROLL_TEXT_INPUT", // = 99
"LOAD_URL", // = 100;
@@ -769,7 +776,7 @@ final class WebViewCore {
"SET_BACKGROUND_COLOR", // = 126;
"SET_MOVE_FOCUS", // = 127
"SAVE_DOCUMENT_STATE", // = 128;
- "GET_SELECTION", // = 129;
+ "129", // = 129;
"WEBKIT_DRAW", // = 130;
"SYNC_SCROLL", // = 131;
"POST_URL", // = 132;
@@ -791,6 +798,7 @@ final class WebViewCore {
class EventHub {
// Message Ids
+ static final int REQUEST_LABEL = 97;
static final int UPDATE_FRAME_CACHE_IF_LOADING = 98;
static final int SCROLL_TEXT_INPUT = 99;
static final int LOAD_URL = 100;
@@ -821,7 +829,7 @@ final class WebViewCore {
static final int SET_BACKGROUND_COLOR = 126;
static final int SET_MOVE_FOCUS = 127;
static final int SAVE_DOCUMENT_STATE = 128;
- static final int GET_SELECTION = 129;
+
static final int WEBKIT_DRAW = 130;
static final int SYNC_SCROLL = 131;
static final int POST_URL = 132;
@@ -870,6 +878,8 @@ final class WebViewCore {
static final int POPULATE_VISITED_LINKS = 181;
+ static final int HIDE_FULLSCREEN = 182;
+
// private message ids
private static final int DESTROY = 200;
@@ -901,11 +911,11 @@ final class WebViewCore {
@Override
public void handleMessage(Message msg) {
if (DebugFlags.WEB_VIEW_CORE) {
- Log.v(LOGTAG, (msg.what < UPDATE_FRAME_CACHE_IF_LOADING
+ Log.v(LOGTAG, (msg.what < REQUEST_LABEL
|| msg.what
> VALID_NODE_BOUNDS ? Integer.toString(msg.what)
: HandlerDebugString[msg.what
- - UPDATE_FRAME_CACHE_IF_LOADING])
+ - REQUEST_LABEL])
+ " arg1=" + msg.arg1 + " arg2=" + msg.arg2
+ " obj=" + msg.obj);
}
@@ -926,6 +936,19 @@ final class WebViewCore {
}
break;
+ case REQUEST_LABEL:
+ if (mWebView != null) {
+ int nodePointer = msg.arg2;
+ String label = nativeRequestLabel(msg.arg1,
+ nodePointer);
+ if (label != null && label.length() > 0) {
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.RETURN_LABEL, nodePointer,
+ 0, label).sendToTarget();
+ }
+ }
+ break;
+
case UPDATE_FRAME_CACHE_IF_LOADING:
nativeUpdateFrameCacheIfLoading();
break;
@@ -1243,13 +1266,6 @@ final class WebViewCore {
nativeSetBackgroundColor(msg.arg1);
break;
- case GET_SELECTION:
- String str = nativeGetSelection((Region) msg.obj);
- Message.obtain(mWebView.mPrivateHandler
- , WebView.UPDATE_CLIPBOARD, str)
- .sendToTarget();
- break;
-
case DUMP_DOMTREE:
nativeDumpDomTree(msg.arg1 == 1);
break;
@@ -1313,6 +1329,10 @@ final class WebViewCore {
message);
break;
}
+
+ case HIDE_FULLSCREEN:
+ nativeFullScreenPluginHidden(msg.arg1);
+ break;
}
}
};
@@ -1894,6 +1914,33 @@ final class WebViewCore {
}
}
+ private static boolean mRepaintScheduled = false;
+
+ /*
+ * Called by the WebView thread
+ */
+ /* package */ void signalRepaintDone() {
+ mRepaintScheduled = false;
+ }
+
+ // called by JNI
+ private void sendImmediateRepaint() {
+ if (mWebView != null && !mRepaintScheduled) {
+ mRepaintScheduled = true;
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.IMMEDIATE_REPAINT_MSG_ID).sendToTarget();
+ }
+ }
+
+ // called by JNI
+ private void setRootLayer(int layer) {
+ if (mWebView != null) {
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.SET_ROOT_LAYER_MSG_ID,
+ layer, 0).sendToTarget();
+ }
+ }
+
/* package */ WebView getWebView() {
return mWebView;
}
@@ -1910,7 +1957,14 @@ final class WebViewCore {
if (mWebView == null) return;
- setupViewport(standardLoad || mRestoredScale > 0);
+ boolean updateRestoreState = standardLoad || mRestoredScale > 0;
+ setupViewport(updateRestoreState);
+ // if updateRestoreState is true, ViewManager.postReadyToDrawAll() will
+ // be called after the WebView restore the state. If updateRestoreState
+ // is false, start to draw now as it is ready.
+ if (!updateRestoreState) {
+ mWebView.mViewManager.postReadyToDrawAll();
+ }
// reset the scroll position, the restored offset and scales
mWebkitScrollX = mWebkitScrollY = mRestoredX = mRestoredY
@@ -2153,7 +2207,7 @@ final class WebViewCore {
}
private native void nativeUpdateFrameCacheIfLoading();
-
+ private native String nativeRequestLabel(int framePtr, int nodePtr);
/**
* Scroll the focused textfield to (xPercent, y) in document space
*/
@@ -2236,35 +2290,53 @@ final class WebViewCore {
// called by JNI. PluginWidget function to launch a full-screen view using a
// View object provided by the plugin class.
- private void showFullScreenPlugin(WebkitPlugin webkitPlugin, final int npp) {
+ private void showFullScreenPlugin(WebkitPlugin webkitPlugin, final int npp,
+ int x, int y, int width, int height) {
if (mWebView == null) {
return;
}
- final FullScreenDrawingModel surface = webkitPlugin.getFullScreenSurface();
+ final SurfaceDrawingModel surface = webkitPlugin.getFullScreenSurface();
if(surface == null) {
- Log.e(LOGTAG, "Attempted to create an full-screen surface with a null drawing model");
+ Log.e(LOGTAG, "Attempted to create an full-screen surface with a " +
+ "null drawing model");
return;
}
- WebChromeClient.CustomViewCallback callback = new WebChromeClient.CustomViewCallback() {
- public void onCustomViewHidden() {
- if (surface != null) {
- surface.onSurfaceRemoved();
- nativeFullScreenPluginHidden(npp);
- }
- }
- };
-
- mCallbackProxy.showCustomView(surface.getSurface(), callback);
+ PluginFullScreenData data = new PluginFullScreenData();
+ data.mView = surface.getSurface();
+ data.mNpp = npp;
+ data.mDocX = x;
+ data.mDocY = y;
+ data.mDocWidth = width;
+ data.mDocHeight = height;
+ mWebView.mPrivateHandler.obtainMessage(WebView.SHOW_FULLSCREEN, data)
+ .sendToTarget();
}
+ // called by JNI
private void hideFullScreenPlugin() {
if (mWebView == null) {
return;
}
+ mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN)
+ .sendToTarget();
+ }
+
+ // called by JNI
+ private void updateFullScreenPlugin(int x, int y, int width, int height) {
+ if (mWebView == null) {
+ return;
+ }
- mCallbackProxy.hideCustomView();
+ PluginFullScreenData data = new PluginFullScreenData();
+ data.mDocX = x;
+ data.mDocY = y;
+ data.mDocWidth = width;
+ data.mDocHeight = height;
+ // null mView and mNpp to indicate it is an update
+ mWebView.mPrivateHandler.obtainMessage(WebView.SHOW_FULLSCREEN, data)
+ .sendToTarget();
}
// called by JNI. PluginWidget functions for creating an embedded View for
diff --git a/core/java/android/webkit/plugin/FullScreenDrawingModel.java b/core/java/android/webkit/plugin/FullScreenDrawingModel.java
deleted file mode 100644
index fe9d197..0000000
--- a/core/java/android/webkit/plugin/FullScreenDrawingModel.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2009, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package android.webkit.plugin;
-
-/**
- *
- * @hide pending API solidification
- */
-public interface FullScreenDrawingModel extends SurfaceDrawingModel {
-
- public void onSurfaceRemoved();
-
-}
diff --git a/core/java/android/webkit/plugin/WebkitPlugin.java b/core/java/android/webkit/plugin/WebkitPlugin.java
index af02cdc..3d13c1c 100644
--- a/core/java/android/webkit/plugin/WebkitPlugin.java
+++ b/core/java/android/webkit/plugin/WebkitPlugin.java
@@ -30,7 +30,7 @@ package android.webkit.plugin;
*/
public interface WebkitPlugin {
- SurfaceDrawingModel getEmbeddedSurface();
- FullScreenDrawingModel getFullScreenSurface();
+ SurfaceDrawingModel getEmbeddedSurface();
+ SurfaceDrawingModel getFullScreenSurface();
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 92ff315..e241c77 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -127,11 +127,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
static final int TOUCH_MODE_FLING = 4;
/**
- * Indicates that the user is currently dragging the fast scroll thumb
- */
- static final int TOUCH_MODE_FAST_SCROLL = 5;
-
- /**
* Regular layout - usually an unsolicited layout from the view system
*/
static final int LAYOUT_NORMAL = 0;
@@ -440,6 +435,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private Runnable mClearScrollingCache;
private int mMinimumVelocity;
private int mMaximumVelocity;
+
+ final boolean[] mIsScrap = new boolean[1];
/**
* Interface definition for a callback to be invoked when the list or grid
@@ -1239,9 +1236,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* converting an old view or making a new one.
*
* @param position The position to display
+ * @param isScrap Array of at least 1 boolean, the first entry will become true if
+ * the returned view was taken from the scrap heap, false if otherwise.
+ *
* @return A view displaying the data associated with the specified position
*/
- View obtainView(int position) {
+ View obtainView(int position, boolean[] isScrap) {
+ isScrap[0] = false;
View scrapView;
scrapView = mRecycler.getScrapView(position);
@@ -1269,6 +1270,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
ViewDebug.trace(scrapView, ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP,
position, -1);
}
+ } else {
+ isScrap[0] = true;
}
} else {
child = mAdapter.getView(position, null, this);
@@ -1543,6 +1546,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// Dismiss the popup in case onSaveInstanceState() was not invoked
dismissPopup();
+ // Detach any view left in the scrap heap
+ mRecycler.clear();
+
final ViewTreeObserver treeObserver = getViewTreeObserver();
if (treeObserver != null) {
treeObserver.removeOnTouchModeChangeListener(this);
@@ -1636,6 +1642,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mDataChanged) return;
if (mAdapter != null && mItemCount > 0 &&
+ mClickMotionPosition != INVALID_POSITION &&
mClickMotionPosition < mAdapter.getCount() && sameWindow()) {
performItemClick(mChild, mClickMotionPosition, getAdapter().getItemId(
mClickMotionPosition));
@@ -2969,7 +2976,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
break;
case KeyEvent.KEYCODE_SPACE:
// Only send spaces once we are filtered
- okToSend = mFiltered = true;
+ okToSend = mFiltered;
break;
}
@@ -3594,12 +3601,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
for (int i = 0; i < count; ++i) {
final View victim = activeViews[i];
if (victim != null) {
- int whichScrap = ((AbsListView.LayoutParams)
- victim.getLayoutParams()).viewType;
+ int whichScrap = ((AbsListView.LayoutParams) victim.getLayoutParams()).viewType;
activeViews[i] = null;
if (whichScrap == AdapterView.ITEM_VIEW_TYPE_IGNORE) {
+ removeDetachedView(victim, false);
// Do not move views that should be ignored
continue;
}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index d25530b..d6dd872 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -26,7 +26,6 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
public abstract class AbsSeekBar extends ProgressBar {
-
private Drawable mThumb;
private int mThumbOffset;
@@ -66,8 +65,9 @@ public abstract class AbsSeekBar extends ProgressBar {
Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
setThumb(thumb); // will guess mThumbOffset if thumb != null...
// ...but allow layout to override this
- int thumbOffset =
- a.getDimensionPixelOffset(com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
+ int thumbOffset = a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
+ setThumbOffset(thumbOffset);
a.recycle();
a = context.obtainStyledAttributes(attrs,
@@ -91,7 +91,7 @@ public abstract class AbsSeekBar extends ProgressBar {
// Assuming the thumb drawable is symmetric, set the thumb offset
// such that the thumb will hang halfway off either edge of the
// progress bar.
- mThumbOffset = (int)thumb.getIntrinsicWidth() / 2;
+ mThumbOffset = thumb.getIntrinsicWidth() / 2;
}
mThumb = thumb;
invalidate();
@@ -368,20 +368,21 @@ public abstract class AbsSeekBar extends ProgressBar {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- int progress = getProgress();
-
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (progress <= 0) break;
- setProgress(progress - mKeyProgressIncrement, true);
- onKeyChange();
- return true;
-
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (progress >= getMax()) break;
- setProgress(progress + mKeyProgressIncrement, true);
- onKeyChange();
- return true;
+ if (isEnabled()) {
+ int progress = getProgress();
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (progress <= 0) break;
+ setProgress(progress - mKeyProgressIncrement, true);
+ onKeyChange();
+ return true;
+
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (progress >= getMax()) break;
+ setProgress(progress + mKeyProgressIncrement, true);
+ onKeyChange();
+ return true;
+ }
}
return super.onKeyDown(keyCode, event);
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index ce985e3..b455d47 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1485,8 +1485,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* @return the view for the specified item
*/
@Override
- protected View obtainView(int position) {
- View view = super.obtainView(position);
+ View obtainView(int position, boolean[] isScrap) {
+ View view = super.obtainView(position, isScrap);
if (view instanceof TextView) {
((TextView) view).setHorizontallyScrolling(true);
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index ffe9908..2e91e52 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -931,7 +931,7 @@ public class GridView extends AbsListView {
mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
final int count = mItemCount;
if (count > 0) {
- final View child = obtainView(0);
+ final View child = obtainView(0, mIsScrap);
AbsListView.LayoutParams p = (AbsListView.LayoutParams)child.getLayoutParams();
if (p == null) {
@@ -1203,7 +1203,7 @@ public class GridView extends AbsListView {
View child;
if (!mDataChanged) {
- // Try to use an exsiting view for this position
+ // Try to use an existing view for this position
child = mRecycler.getActiveView(position);
if (child != null) {
// Found it -- we're using an existing child
@@ -1215,10 +1215,10 @@ public class GridView extends AbsListView {
// Make a new view for this position, or convert an unused view if
// possible
- child = obtainView(position);
+ child = obtainView(position, mIsScrap);
// This needs to be positioned and measured
- setupChild(child, position, y, flow, childrenLeft, selected, false, where);
+ setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0], where);
return child;
}
diff --git a/core/java/android/widget/ImageButton.java b/core/java/android/widget/ImageButton.java
index d417e40..2fc29bc 100644
--- a/core/java/android/widget/ImageButton.java
+++ b/core/java/android/widget/ImageButton.java
@@ -44,11 +44,11 @@ import java.util.Map;
* <pre>
* &lt;?xml version="1.0" encoding="utf-8"?&gt;
* &lt;selector xmlns:android="http://schemas.android.com/apk/res/android"&gt;
- * &lt;item android:drawable="@drawable/button_normal" /&gt; &lt;!-- default --&gt;
* &lt;item android:state_pressed="true"
* android:drawable="@drawable/button_pressed" /&gt; &lt;!-- pressed --&gt;
* &lt;item android:state_focused="true"
* android:drawable="@drawable/button_focused" /&gt; &lt;!-- focused --&gt;
+ * &lt;item android:drawable="@drawable/button_normal" /&gt; &lt;!-- default --&gt;
* &lt;/selector&gt;</pre>
*
* <p>Save the XML file in your project {@code res/drawable/} folder and then
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 8f24041..3853359 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -491,8 +491,16 @@ public class ImageView extends View {
}
} else if (mUri != null) {
String scheme = mUri.getScheme();
- if (ContentResolver.SCHEME_CONTENT.equals(scheme)
- || ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)
+ if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
+ try {
+ // Load drawable through Resources, to get the source density information
+ ContentResolver.OpenResourceIdResult r =
+ mContext.getContentResolver().getResourceId(mUri);
+ d = r.r.getDrawable(r.id);
+ } catch (Exception e) {
+ Log.w("ImageView", "Unable to open content: " + mUri, e);
+ }
+ } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
|| ContentResolver.SCHEME_FILE.equals(scheme)) {
try {
d = Drawable.createFromStream(
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index b574d45..f4008f9 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1033,7 +1033,7 @@ public class ListView extends AbsListView {
mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED ||
heightMode == MeasureSpec.UNSPECIFIED)) {
- final View child = obtainView(0);
+ final View child = obtainView(0, mIsScrap);
measureScrapChild(child, 0, widthMeasureSpec);
@@ -1142,9 +1142,10 @@ public class ListView extends AbsListView {
endPosition = (endPosition == NO_POSITION) ? adapter.getCount() - 1 : endPosition;
final AbsListView.RecycleBin recycleBin = mRecycler;
final boolean recyle = recycleOnMeasure();
+ final boolean[] isScrap = mIsScrap;
for (i = startPosition; i <= endPosition; ++i) {
- child = obtainView(i);
+ child = obtainView(i, isScrap);
measureScrapChild(child, i, widthMeasureSpec);
@@ -1665,10 +1666,10 @@ public class ListView extends AbsListView {
}
// Make a new view for this position, or convert an unused view if possible
- child = obtainView(position);
+ child = obtainView(position, mIsScrap);
// This needs to be positioned and measured
- setupChild(child, position, y, flow, childrenLeft, selected, false);
+ setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);
return child;
}
@@ -2823,17 +2824,19 @@ public class ListView extends AbsListView {
private View addViewAbove(View theView, int position) {
int abovePosition = position - 1;
- View view = obtainView(abovePosition);
+ View view = obtainView(abovePosition, mIsScrap);
int edgeOfNewChild = theView.getTop() - mDividerHeight;
- setupChild(view, abovePosition, edgeOfNewChild, false, mListPadding.left, false, false);
+ setupChild(view, abovePosition, edgeOfNewChild, false, mListPadding.left,
+ false, mIsScrap[0]);
return view;
}
private View addViewBelow(View theView, int position) {
int belowPosition = position + 1;
- View view = obtainView(belowPosition);
+ View view = obtainView(belowPosition, mIsScrap);
int edgeOfNewChild = theView.getBottom() + mDividerHeight;
- setupChild(view, belowPosition, edgeOfNewChild, true, mListPadding.left, false, false);
+ setupChild(view, belowPosition, edgeOfNewChild, true, mListPadding.left,
+ false, mIsScrap[0]);
return view;
}
@@ -3080,13 +3083,19 @@ public class ListView extends AbsListView {
if (gainFocus && previouslyFocusedRect != null) {
previouslyFocusedRect.offset(mScrollX, mScrollY);
+ final ListAdapter adapter = mAdapter;
+ final int firstPosition = mFirstPosition;
+ // Don't cache the result of getChildCount here, it could change in layoutChildren.
+ if (adapter.getCount() < getChildCount() + firstPosition) {
+ mLayoutMode = LAYOUT_NORMAL;
+ layoutChildren();
+ }
+
// figure out which item should be selected based on previously
// focused rect
Rect otherRect = mTempRect;
int minDistance = Integer.MAX_VALUE;
final int childCount = getChildCount();
- final int firstPosition = mFirstPosition;
- final ListAdapter adapter = mAdapter;
for (int i = 0; i < childCount; i++) {
// only consider selectable views
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index e19a93d..533c607 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -45,8 +45,7 @@ import java.util.ArrayList;
/**
* A Layout where the positions of the children can be described in relation to each other or to the
- * parent. For the sake of efficiency, the relations between views are evaluated in one pass, so if
- * view Y is dependent on the position of view X, make sure the view X comes first in the layout.
+ * parent.
*
* <p>
* Note that you cannot have a circular dependency between the size of the RelativeLayout and the
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index b847e57..3003580 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -26,6 +26,7 @@ import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -37,7 +38,6 @@ import android.view.ViewGroup;
import android.view.LayoutInflater.Filter;
import android.view.View.OnClickListener;
-import java.lang.Class;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -137,11 +137,21 @@ public class RemoteViews implements Parcelable, Filter {
if (target != null && pendingIntent != null) {
OnClickListener listener = new OnClickListener() {
public void onClick(View v) {
- int[] pos = new int[2];
+ // Find target view location in screen coordinates and
+ // fill into PendingIntent before sending.
+ final float appScale = v.getContext().getResources()
+ .getCompatibilityInfo().applicationScale;
+ final int[] pos = new int[2];
v.getLocationOnScreen(pos);
- Intent intent = new Intent();
- intent.setSourceBounds(new Rect(pos[0], pos[1],
- pos[0]+v.getWidth(), pos[1]+v.getHeight()));
+
+ final Rect rect = new Rect();
+ rect.left = (int) (pos[0] * appScale + 0.5f);
+ rect.top = (int) (pos[1] * appScale + 0.5f);
+ rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
+ rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
+
+ final Intent intent = new Intent();
+ intent.setSourceBounds(rect);
try {
// TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
v.getContext().startIntentSender(
@@ -273,6 +283,7 @@ public class RemoteViews implements Parcelable, Filter {
static final int CHAR_SEQUENCE = 10;
static final int URI = 11;
static final int BITMAP = 12;
+ static final int BUNDLE = 13;
int viewId;
String methodName;
@@ -332,6 +343,9 @@ public class RemoteViews implements Parcelable, Filter {
case BITMAP:
this.value = Bitmap.CREATOR.createFromParcel(in);
break;
+ case BUNDLE:
+ this.value = in.readBundle();
+ break;
default:
break;
}
@@ -384,6 +398,9 @@ public class RemoteViews implements Parcelable, Filter {
case BITMAP:
((Bitmap)this.value).writeToParcel(out, flags);
break;
+ case BUNDLE:
+ out.writeBundle((Bundle) this.value);
+ break;
default:
break;
}
@@ -415,6 +432,8 @@ public class RemoteViews implements Parcelable, Filter {
return Uri.class;
case BITMAP:
return Bitmap.class;
+ case BUNDLE:
+ return Bundle.class;
default:
return null;
}
@@ -876,6 +895,17 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * Call a method taking one Bundle on a view in the layout for this RemoteViews.
+ *
+ * @param viewId The id of the view whose text should change
+ * @param methodName The name of the method to call.
+ * @param value The value to pass to the method.
+ */
+ public void setBundle(int viewId, String methodName, Bundle value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BUNDLE, value));
+ }
+
+ /**
* Inflates the view hierarchy represented by this object and applies
* all of the actions.
*
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index 9dd4d15..479965a 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -25,7 +25,6 @@ import android.net.Uri;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.WeakHashMap;
/**
* An easy adapter to map static data to views defined in an XML file. You can specify the data
@@ -58,7 +57,6 @@ public class SimpleAdapter extends BaseAdapter implements Filterable {
private int mResource;
private int mDropDownResource;
private LayoutInflater mInflater;
- private final WeakHashMap<View, View[]> mHolders = new WeakHashMap<View, View[]>();
private SimpleFilter mFilter;
private ArrayList<Map<String, ?>> mUnfilteredData;
@@ -121,16 +119,6 @@ public class SimpleAdapter extends BaseAdapter implements Filterable {
View v;
if (convertView == null) {
v = mInflater.inflate(resource, parent, false);
-
- final int[] to = mTo;
- final int count = to.length;
- final View[] holder = new View[count];
-
- for (int i = 0; i < count; i++) {
- holder[i] = v.findViewById(to[i]);
- }
-
- mHolders.put(v, holder);
} else {
v = convertView;
}
@@ -162,13 +150,12 @@ public class SimpleAdapter extends BaseAdapter implements Filterable {
}
final ViewBinder binder = mViewBinder;
- final View[] holder = mHolders.get(view);
final String[] from = mFrom;
final int[] to = mTo;
final int count = to.length;
for (int i = 0; i < count; i++) {
- final View v = holder[i];
+ final View v = view.findViewById(to[i]);
if (v != null) {
final Object data = dataSet.get(from[i]);
String text = data == null ? "" : data.toString();
@@ -187,7 +174,8 @@ public class SimpleAdapter extends BaseAdapter implements Filterable {
((Checkable) v).setChecked((Boolean) data);
} else {
throw new IllegalStateException(v.getClass().getName() +
- " should be bound to a Boolean, not a " + data.getClass());
+ " should be bound to a Boolean, not a " +
+ (data == null ? "<unknown type>" : data.getClass()));
}
} else if (v instanceof TextView) {
// Note: keep the instanceof TextView check at the bottom of these
diff --git a/core/java/android/widget/SimpleCursorAdapter.java b/core/java/android/widget/SimpleCursorAdapter.java
index 436b79b..7d3459e 100644
--- a/core/java/android/widget/SimpleCursorAdapter.java
+++ b/core/java/android/widget/SimpleCursorAdapter.java
@@ -20,9 +20,6 @@ import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.WeakHashMap;
/**
* An easy adapter to map columns from a cursor to TextViews or ImageViews
@@ -66,7 +63,6 @@ public class SimpleCursorAdapter extends ResourceCursorAdapter {
private CursorToStringConverter mCursorToStringConverter;
private ViewBinder mViewBinder;
private String[] mOriginalFrom;
- private final WeakHashMap<View, View[]> mHolders = new WeakHashMap<View, View[]>();
/**
* Constructor.
@@ -91,29 +87,6 @@ public class SimpleCursorAdapter extends ResourceCursorAdapter {
findColumns(from);
}
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return generateViewHolder(super.newView(context, cursor, parent));
- }
-
- @Override
- public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) {
- return generateViewHolder(super.newDropDownView(context, cursor, parent));
- }
-
- private View generateViewHolder(View v) {
- final int[] to = mTo;
- final int count = to.length;
- final View[] holder = new View[count];
-
- for (int i = 0; i < count; i++) {
- holder[i] = v.findViewById(to[i]);
- }
- mHolders.put(v, holder);
-
- return v;
- }
-
/**
* Binds all of the field names passed into the "to" parameter of the
* constructor with their corresponding cursor columns as specified in the
@@ -140,13 +113,13 @@ public class SimpleCursorAdapter extends ResourceCursorAdapter {
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
- final View[] holder = mHolders.get(view);
final ViewBinder binder = mViewBinder;
final int count = mTo.length;
final int[] from = mFrom;
+ final int[] to = mTo;
for (int i = 0; i < count; i++) {
- final View v = holder[i];
+ final View v = view.findViewById(to[i]);
if (v != null) {
boolean bound = false;
if (binder != null) {
diff --git a/core/java/com/android/internal/database/ArrayListCursor.java b/core/java/com/android/internal/database/ArrayListCursor.java
deleted file mode 100644
index 2e1d8f1..0000000
--- a/core/java/com/android/internal/database/ArrayListCursor.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.database;
-
-import android.database.AbstractCursor;
-import android.database.CursorWindow;
-
-import java.lang.System;
-import java.util.ArrayList;
-
-/**
- * A convenience class that presents a two-dimensional ArrayList
- * as a Cursor.
- */
-public class ArrayListCursor extends AbstractCursor {
- private String[] mColumnNames;
- private ArrayList<Object>[] mRows;
-
- @SuppressWarnings({"unchecked"})
- public ArrayListCursor(String[] columnNames, ArrayList<ArrayList> rows) {
- int colCount = columnNames.length;
- boolean foundID = false;
- // Add an _id column if not in columnNames
- for (int i = 0; i < colCount; ++i) {
- if (columnNames[i].compareToIgnoreCase("_id") == 0) {
- mColumnNames = columnNames;
- foundID = true;
- break;
- }
- }
-
- if (!foundID) {
- mColumnNames = new String[colCount + 1];
- System.arraycopy(columnNames, 0, mColumnNames, 0, columnNames.length);
- mColumnNames[colCount] = "_id";
- }
-
- int rowCount = rows.size();
- mRows = new ArrayList[rowCount];
-
- for (int i = 0; i < rowCount; ++i) {
- mRows[i] = rows.get(i);
- if (!foundID) {
- mRows[i].add(i);
- }
- }
- }
-
- @Override
- public void fillWindow(int position, CursorWindow window) {
- if (position < 0 || position > getCount()) {
- return;
- }
-
- window.acquireReference();
- try {
- int oldpos = mPos;
- mPos = position - 1;
- window.clear();
- window.setStartPosition(position);
- int columnNum = getColumnCount();
- window.setNumColumns(columnNum);
- while (moveToNext() && window.allocRow()) {
- for (int i = 0; i < columnNum; i++) {
- final Object data = mRows[mPos].get(i);
- if (data != null) {
- if (data instanceof byte[]) {
- byte[] field = (byte[]) data;
- if (!window.putBlob(field, mPos, i)) {
- window.freeLastRow();
- break;
- }
- } else {
- String field = data.toString();
- if (!window.putString(field, mPos, i)) {
- window.freeLastRow();
- break;
- }
- }
- } else {
- if (!window.putNull(mPos, i)) {
- window.freeLastRow();
- break;
- }
- }
- }
- }
-
- mPos = oldpos;
- } catch (IllegalStateException e){
- // simply ignore it
- } finally {
- window.releaseReference();
- }
- }
-
- @Override
- public int getCount() {
- return mRows.length;
- }
-
- @Override
- public boolean deleteRow() {
- return false;
- }
-
- @Override
- public String[] getColumnNames() {
- return mColumnNames;
- }
-
- @Override
- public byte[] getBlob(int columnIndex) {
- return (byte[]) mRows[mPos].get(columnIndex);
- }
-
- @Override
- public String getString(int columnIndex) {
- Object cell = mRows[mPos].get(columnIndex);
- return (cell == null) ? null : cell.toString();
- }
-
- @Override
- public short getShort(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.shortValue();
- }
-
- @Override
- public int getInt(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.intValue();
- }
-
- @Override
- public long getLong(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.longValue();
- }
-
- @Override
- public float getFloat(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.floatValue();
- }
-
- @Override
- public double getDouble(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.doubleValue();
- }
-
- @Override
- public boolean isNull(int columnIndex) {
- return mRows[mPos].get(columnIndex) == null;
- }
-}
diff --git a/core/java/com/android/internal/net/DbSSLSessionCache.java b/core/java/com/android/internal/net/DbSSLSessionCache.java
deleted file mode 100644
index 842d40b..0000000
--- a/core/java/com/android/internal/net/DbSSLSessionCache.java
+++ /dev/null
@@ -1,289 +0,0 @@
-// Copyright 2009 The Android Open Source Project
-
-package com.android.internal.net;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.SQLException;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.util.Log;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.net.ssl.SSLSession;
-
-/**
- * Hook into harmony SSL cache to persist the SSL sessions.
- *
- * Current implementation is suitable for saving a small number of hosts -
- * like google services. It can be extended with expiration and more features
- * to support more hosts.
- *
- * {@hide}
- */
-public class DbSSLSessionCache implements SSLClientSessionCache {
- private static final String TAG = "DbSSLSessionCache";
-
- /**
- * Table where sessions are stored.
- */
- public static final String SSL_CACHE_TABLE = "ssl_sessions";
-
- private static final String SSL_CACHE_ID = "_id";
-
- /**
- * Key is host:port - port is not optional.
- */
- private static final String SSL_CACHE_HOSTPORT = "hostport";
-
- /**
- * Base64-encoded DER value of the session.
- */
- private static final String SSL_CACHE_SESSION = "session";
-
- /**
- * Time when the record was added - should be close to the time
- * of the initial session negotiation.
- */
- private static final String SSL_CACHE_TIME_SEC = "time_sec";
-
- public static final String DATABASE_NAME = "ssl_sessions.db";
-
- public static final int DATABASE_VERSION = 2;
-
- /** public for testing
- */
- public static final int SSL_CACHE_ID_COL = 0;
- public static final int SSL_CACHE_HOSTPORT_COL = 1;
- public static final int SSL_CACHE_SESSION_COL = 2;
- public static final int SSL_CACHE_TIME_SEC_COL = 3;
-
- public static final int MAX_CACHE_SIZE = 256;
-
- private final Map<String, byte[]> mExternalCache =
- new HashMap<String, byte[]>();
-
-
- private DatabaseHelper mDatabaseHelper;
-
- private boolean mNeedsCacheLoad = true;
-
- public static final String[] PROJECTION = new String[] {
- SSL_CACHE_ID,
- SSL_CACHE_HOSTPORT,
- SSL_CACHE_SESSION,
- SSL_CACHE_TIME_SEC
- };
-
- private static final Map<String,DbSSLSessionCache> sInstances =
- new HashMap<String,DbSSLSessionCache>();
-
- /**
- * Returns a singleton instance of the DbSSLSessionCache that should be used for this
- * context's package.
- *
- * @param context The context that should be used for getting/creating the singleton instance.
- * @return The singleton instance for the context's package.
- */
- public static synchronized DbSSLSessionCache getInstanceForPackage(Context context) {
- String packageName = context.getPackageName();
- if (sInstances.containsKey(packageName)) {
- return sInstances.get(packageName);
- }
- DbSSLSessionCache cache = new DbSSLSessionCache(context);
- sInstances.put(packageName, cache);
- return cache;
- }
-
- /**
- * Create a SslSessionCache instance, using the specified context to
- * initialize the database.
- *
- * This constructor will use the default database - created for the application
- * context.
- *
- * @param activityContext
- */
- private DbSSLSessionCache(Context activityContext) {
- Context appContext = activityContext.getApplicationContext();
- mDatabaseHelper = new DatabaseHelper(appContext);
- }
-
- /**
- * Create a SslSessionCache that uses a specific database.
- *
- *
- * @param database
- */
- public DbSSLSessionCache(DatabaseHelper database) {
- this.mDatabaseHelper = database;
- }
-
- public void putSessionData(SSLSession session, byte[] der) {
- if (mDatabaseHelper == null) {
- return;
- }
- synchronized (this.getClass()) {
- SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
- if (mExternalCache.size() == MAX_CACHE_SIZE) {
- // remove oldest.
- // TODO: check if the new one is in cached already ( i.e. update ).
- Cursor byTime = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE,
- PROJECTION, null, null, null, null, SSL_CACHE_TIME_SEC);
- if (byTime.moveToFirst()) {
- // TODO: can I do byTime.deleteRow() ?
- String hostPort = byTime.getString(SSL_CACHE_HOSTPORT_COL);
- db.delete(SSL_CACHE_TABLE,
- SSL_CACHE_HOSTPORT + "= ?" , new String[] { hostPort });
- mExternalCache.remove(hostPort);
- } else {
- Log.w(TAG, "No rows found");
- // something is wrong, clear it
- clear();
- }
- }
- // Serialize native session to standard DER encoding
- long t0 = System.currentTimeMillis();
-
- String b64 = new String(Base64.encodeBase64(der));
- String key = session.getPeerHost() + ":" + session.getPeerPort();
-
- ContentValues values = new ContentValues();
- values.put(SSL_CACHE_HOSTPORT, key);
- values.put(SSL_CACHE_SESSION, b64);
- values.put(SSL_CACHE_TIME_SEC, System.currentTimeMillis() / 1000);
-
- mExternalCache.put(key, der);
-
- try {
- db.insert(SSL_CACHE_TABLE, null /*nullColumnHack */ , values);
- } catch(SQLException ex) {
- // Ignore - nothing we can do to recover, and caller shouldn't
- // be affected.
- Log.w(TAG, "Ignoring SQL exception when caching session", ex);
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- long t1 = System.currentTimeMillis();
- Log.d(TAG, "New SSL session " + session.getPeerHost() +
- " DER len: " + der.length + " " + (t1 - t0));
- }
- }
-
- }
-
- public byte[] getSessionData(String host, int port) {
- // Current (simple) implementation does a single lookup to DB, then saves
- // all entries to the cache.
-
- // This works for google services - i.e. small number of certs.
- // If we extend this to all processes - we should hold a separate cache
- // or do lookups to DB each time.
- if (mDatabaseHelper == null) {
- return null;
- }
- synchronized(this.getClass()) {
- if (mNeedsCacheLoad) {
- // Don't try to load again, if something is wrong on the first
- // request it'll likely be wrong each time.
- mNeedsCacheLoad = false;
- long t0 = System.currentTimeMillis();
-
- Cursor cur = null;
- try {
- cur = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE,
- PROJECTION, null, null, null, null, null);
- if (cur.moveToFirst()) {
- do {
- String hostPort = cur.getString(SSL_CACHE_HOSTPORT_COL);
- String value = cur.getString(SSL_CACHE_SESSION_COL);
-
- if (hostPort == null || value == null) {
- continue;
- }
- // TODO: blob support ?
- byte[] der = Base64.decodeBase64(value.getBytes());
- mExternalCache.put(hostPort, der);
- } while (cur.moveToNext());
-
- }
- } catch (SQLException ex) {
- Log.d(TAG, "Error loading SSL cached entries ", ex);
- } finally {
- if (cur != null) {
- cur.close();
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- long t1 = System.currentTimeMillis();
- Log.d(TAG, "LOADED CACHED SSL " + (t1 - t0) + " ms");
- }
- }
- }
-
- String key = host + ":" + port;
-
- return mExternalCache.get(key);
- }
- }
-
- /**
- * Reset the database and internal state.
- * Used for testing or to free space.
- */
- public void clear() {
- synchronized(this) {
- try {
- mExternalCache.clear();
- mNeedsCacheLoad = true;
- mDatabaseHelper.getWritableDatabase().delete(SSL_CACHE_TABLE,
- null, null);
- } catch (SQLException ex) {
- Log.d(TAG, "Error removing SSL cached entries ", ex);
- // ignore - nothing we can do about it
- }
- }
- }
-
- public byte[] getSessionData(byte[] id) {
- // We support client side only - the cache will do nothing for
- // server-side sessions.
- return null;
- }
-
- /** Visible for testing.
- */
- public static class DatabaseHelper extends SQLiteOpenHelper {
-
- public DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null /* factory */, DATABASE_VERSION);
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + SSL_CACHE_TABLE + " (" +
- SSL_CACHE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- SSL_CACHE_HOSTPORT + " TEXT UNIQUE ON CONFLICT REPLACE," +
- SSL_CACHE_SESSION + " TEXT," +
- SSL_CACHE_TIME_SEC + " INTEGER" +
- ");");
-
- // No index - we load on startup, index would slow down inserts.
- // If we want to scale this to lots of rows - we could use
- // index, but then we'll hit DB a bit too often ( including
- // negative hits )
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- db.execSQL("DROP TABLE IF EXISTS " + SSL_CACHE_TABLE );
- onCreate(db);
- }
-
- }
-
-}
diff --git a/core/java/com/android/internal/os/LoggingPrintStream.java b/core/java/com/android/internal/os/LoggingPrintStream.java
index b3d6f20..451340b 100644
--- a/core/java/com/android/internal/os/LoggingPrintStream.java
+++ b/core/java/com/android/internal/os/LoggingPrintStream.java
@@ -16,11 +16,17 @@
package com.android.internal.os;
-import java.io.PrintStream;
-import java.io.OutputStream;
import java.io.IOException;
-import java.util.Locale;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
import java.util.Formatter;
+import java.util.Locale;
/**
* A print stream which logs output line by line.
@@ -31,6 +37,27 @@ abstract class LoggingPrintStream extends PrintStream {
private final StringBuilder builder = new StringBuilder();
+ /**
+ * A buffer that is initialized when raw bytes are first written to this
+ * stream. It may contain the leading bytes of multi-byte characters.
+ * Between writes this buffer is always ready to receive data; ie. the
+ * position is at the first unassigned byte and the limit is the capacity.
+ */
+ private ByteBuffer encodedBytes;
+
+ /**
+ * A buffer that is initialized when raw bytes are first written to this
+ * stream. Between writes this buffer is always clear; ie. the position is
+ * zero and the limit is the capacity.
+ */
+ private CharBuffer decodedChars;
+
+ /**
+ * Decodes bytes to characters using the system default charset. Initialized
+ * when raw bytes are first written to this stream.
+ */
+ private CharsetDecoder decoder;
+
protected LoggingPrintStream() {
super(new OutputStream() {
public void write(int oneByte) throws IOException {
@@ -80,20 +107,48 @@ abstract class LoggingPrintStream extends PrintStream {
}
}
- /*
- * We have no idea of how these bytes are encoded, so just ignore them.
- */
-
- /** Ignored. */
- public void write(int oneByte) {}
+ public void write(int oneByte) {
+ write(new byte[] { (byte) oneByte }, 0, 1);
+ }
- /** Ignored. */
@Override
- public void write(byte buffer[]) {}
+ public void write(byte[] buffer) {
+ write(buffer, 0, buffer.length);
+ }
- /** Ignored. */
@Override
- public void write(byte bytes[], int start, int count) {}
+ public synchronized void write(byte bytes[], int start, int count) {
+ if (decoder == null) {
+ encodedBytes = ByteBuffer.allocate(80);
+ decodedChars = CharBuffer.allocate(80);
+ decoder = Charset.defaultCharset().newDecoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+
+ int end = start + count;
+ while (start < end) {
+ // copy some bytes from the array to the long-lived buffer. This
+ // way, if we end with a partial character we don't lose it.
+ int numBytes = Math.min(encodedBytes.remaining(), end - start);
+ encodedBytes.put(bytes, start, numBytes);
+ start += numBytes;
+
+ encodedBytes.flip();
+ CoderResult coderResult;
+ do {
+ // decode bytes from the byte buffer into the char buffer
+ coderResult = decoder.decode(encodedBytes, decodedChars, false);
+
+ // copy chars from the char buffer into our string builder
+ decodedChars.flip();
+ builder.append(decodedChars);
+ decodedChars.clear();
+ } while (coderResult.isOverflow());
+ encodedBytes.compact();
+ }
+ flush(false);
+ }
/** Always returns false. */
@Override
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 2369d25..9e5bdff 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -20,7 +20,7 @@ package com.android.internal.os;
import android.content.Context;
import android.content.res.XmlResourceParser;
-import com.android.internal.util.XmlUtils;
+import com.android.common.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/com/android/internal/os/RecoverySystem.java b/core/java/com/android/internal/os/RecoverySystem.java
deleted file mode 100644
index 3aca683..0000000
--- a/core/java/com/android/internal/os/RecoverySystem.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import android.os.FileUtils;
-import android.os.Power;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * Utility class for interacting with the Android recovery partition.
- * The recovery partition is a small standalone system which can perform
- * operations that are difficult while the main system is running, like
- * upgrading system software or reformatting the data partition.
- * Note that most of these operations must be run as root.
- *
- * @hide
- */
-public class RecoverySystem {
- private static final String TAG = "RecoverySystem"; // for logging
-
- // Used to communicate with recovery. See commands/recovery/recovery.c.
- private static File RECOVERY_DIR = new File("/cache/recovery");
- private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
- private static File LOG_FILE = new File(RECOVERY_DIR, "log");
-
- // Length limits for reading files.
- private static int LOG_FILE_MAX_LENGTH = 8 * 1024;
-
- /**
- * Reboot into the recovery system to install a system update.
- * @param update package to install (must be in /cache or /data).
- * @throws IOException if something goes wrong.
- */
- public static void rebootAndUpdate(File update) throws IOException {
- String path = update.getCanonicalPath();
- if (path.startsWith("/cache/")) {
- path = "CACHE:" + path.substring(7);
- } else if (path.startsWith("/data/")) {
- path = "DATA:" + path.substring(6);
- } else {
- throw new IllegalArgumentException(
- "Must start with /cache or /data: " + path);
- }
- bootCommand("--update_package=" + path);
- }
-
- /**
- * Reboot into the recovery system to wipe the /data partition.
- * @param extras to add to the RECOVERY_COMPLETED intent after rebooting.
- * @throws IOException if something goes wrong.
- */
- public static void rebootAndWipe() throws IOException {
- bootCommand("--wipe_data");
- }
-
- /**
- * Reboot into the recovery system to wipe the /data partition and toggle
- * Encrypted File Systems on/off.
- * @param extras to add to the RECOVERY_COMPLETED intent after rebooting.
- * @throws IOException if something goes wrong.
- * @hide
- */
- public static void rebootAndToggleEFS(boolean efsEnabled) throws IOException {
- if (efsEnabled) {
- bootCommand("--set_encrypted_filesystem=on");
- } else {
- bootCommand("--set_encrypted_filesystem=off");
- }
- }
-
- /**
- * Reboot into the recovery system with the supplied argument.
- * @param arg to pass to the recovery utility.
- * @throws IOException if something goes wrong.
- */
- private static void bootCommand(String arg) throws IOException {
- RECOVERY_DIR.mkdirs(); // In case we need it
- COMMAND_FILE.delete(); // In case it's not writable
- LOG_FILE.delete();
-
- FileWriter command = new FileWriter(COMMAND_FILE);
- try {
- command.write(arg);
- command.write("\n");
- } finally {
- command.close();
- }
-
- // Having written the command file, go ahead and reboot
- Power.reboot("recovery");
- throw new IOException("Reboot failed (no permissions?)");
- }
-
- /**
- * Called after booting to process and remove recovery-related files.
- * @return the log file from recovery, or null if none was found.
- */
- public static String handleAftermath() {
- // Record the tail of the LOG_FILE
- String log = null;
- try {
- log = FileUtils.readTextFile(LOG_FILE, -LOG_FILE_MAX_LENGTH, "...\n");
- } catch (FileNotFoundException e) {
- Log.i(TAG, "No recovery log file");
- } catch (IOException e) {
- Log.e(TAG, "Error reading recovery log", e);
- }
-
- // Delete everything in RECOVERY_DIR
- String[] names = RECOVERY_DIR.list();
- for (int i = 0; names != null && i < names.length; i++) {
- File f = new File(RECOVERY_DIR, names[i]);
- if (!f.delete()) {
- Log.e(TAG, "Can't delete: " + f);
- } else {
- Log.i(TAG, "Deleted: " + f);
- }
- }
-
- return log;
- }
-}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index b7bb72d..57a28e6 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -58,6 +58,10 @@ public class RuntimeInit {
/** true if commonInit() has been called */
private static boolean initialized;
+ private static IBinder mApplicationObject;
+
+ private static volatile boolean mCrashing = false;
+
/**
* Use this to log a message when a thread exits due to an uncaught
* exception. The framework catches these for the main threads, so
@@ -66,14 +70,30 @@ public class RuntimeInit {
private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
try {
- Log.e(TAG, "Uncaught handler: thread " + t.getName()
- + " exiting due to uncaught exception");
- } catch (Throwable error) {
- // Ignore the throwable, since we're in the process of crashing anyway.
- // If we don't, the crash won't happen properly and the process will
- // be left around in a bad state.
+ // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
+ if (mCrashing) return;
+ mCrashing = true;
+
+ if (mApplicationObject == null) {
+ Log.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
+ } else {
+ Log.e(TAG, "FATAL EXCEPTION: " + t.getName(), e);
+ }
+
+ // Bring up crash dialog, wait for it to be dismissed
+ ActivityManagerNative.getDefault().handleApplicationCrash(
+ mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
+ } catch (Throwable t2) {
+ try {
+ Log.e(TAG, "Error reporting crash", t2);
+ } catch (Throwable t3) {
+ // Even Log.e() fails! Oh well.
+ }
+ } finally {
+ // Try everything to make sure this process goes away.
+ Process.killProcess(Process.myPid());
+ System.exit(10);
}
- crash(TAG, e);
}
}
@@ -300,46 +320,22 @@ public class RuntimeInit {
public static native int getQwertyKeyboard();
/**
- * Report a fatal error in the current process. If this is a user-process,
- * a dialog may be displayed informing the user of the error. This
- * function does not return; it forces the current process to exit.
+ * Report a serious error in the current process. May or may not cause
+ * the process to terminate (depends on system settings).
*
- * @param tag to use when logging the error
- * @param t exception that was generated by the error
+ * @param tag to record with the error
+ * @param t exception describing the error site and conditions
*/
- public static void crash(String tag, Throwable t) {
- if (mApplicationObject != null) {
- try {
- // Log exception.
- Log.e(TAG, Log.getStackTraceString(t));
-
- // Show a message to the user.
- IActivityManager am = ActivityManagerNative.getDefault();
- am.handleApplicationError(mApplicationObject, tag,
- new ApplicationErrorReport.CrashInfo(t));
- } catch (Throwable t2) {
- try {
- // Log exception as a string so we don't get in an infinite loop.
- Log.e(TAG, "Error reporting crash: " + Log.getStackTraceString(t2));
- } catch (Throwable t3) {
- // Do nothing, must be OOM so we can't format the message
- }
- } finally {
- // Try everything to make sure this process goes away.
- Process.killProcess(Process.myPid());
- System.exit(10);
- }
- } else {
- try {
- Log.e(TAG, "*** EXCEPTION IN SYSTEM PROCESS. System will crash.");
- Log.e(tag, Log.getStackTraceString(t));
- } catch (Throwable t2) {
- // Do nothing, must be OOM so we can't format the message
- } finally {
- // Try everything to make sure this process goes away.
+ public static void wtf(String tag, Throwable t) {
+ try {
+ if (ActivityManagerNative.getDefault().handleApplicationWtf(
+ mApplicationObject, tag, new ApplicationErrorReport.CrashInfo(t))) {
+ // The Activity Manager has already written us off -- now exit.
Process.killProcess(Process.myPid());
System.exit(10);
}
+ } catch (Throwable t2) {
+ Log.e(TAG, "Error reporting WTF", t2);
}
}
@@ -361,6 +357,4 @@ public class RuntimeInit {
// Register handlers for DDM messages.
android.ddm.DdmRegister.registerHandlers();
}
-
- private static IBinder mApplicationObject;
}
diff --git a/core/java/com/android/internal/util/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java
deleted file mode 100644
index 592a8fa..0000000
--- a/core/java/com/android/internal/util/FastXmlSerializer.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
-
-/**
- * This is a quick and dirty implementation of XmlSerializer that isn't horribly
- * painfully slow like the normal one. It only does what is needed for the
- * specific XML files being written with it.
- */
-public class FastXmlSerializer implements XmlSerializer {
- private static final String ESCAPE_TABLE[] = new String[] {
- null, null, null, null, null, null, null, null, // 0-7
- null, null, null, null, null, null, null, null, // 8-15
- null, null, null, null, null, null, null, null, // 16-23
- null, null, null, null, null, null, null, null, // 24-31
- null, null, "&quot;", null, null, null, "&amp;", null, // 32-39
- null, null, null, null, null, null, null, null, // 40-47
- null, null, null, null, null, null, null, null, // 48-55
- null, null, null, null, "&lt;", null, "&gt;", null, // 56-63
- };
-
- private static final int BUFFER_LEN = 8192;
-
- private final char[] mText = new char[BUFFER_LEN];
- private int mPos;
-
- private Writer mWriter;
-
- private OutputStream mOutputStream;
- private CharsetEncoder mCharset;
- private ByteBuffer mBytes = ByteBuffer.allocate(BUFFER_LEN);
-
- private boolean mInTag;
-
- private void append(char c) throws IOException {
- int pos = mPos;
- if (pos >= (BUFFER_LEN-1)) {
- flush();
- pos = mPos;
- }
- mText[pos] = c;
- mPos = pos+1;
- }
-
- private void append(String str, int i, final int length) throws IOException {
- if (length > BUFFER_LEN) {
- final int end = i + length;
- while (i < end) {
- int next = i + BUFFER_LEN;
- append(str, i, next<end ? BUFFER_LEN : (end-i));
- i = next;
- }
- return;
- }
- int pos = mPos;
- if ((pos+length) > BUFFER_LEN) {
- flush();
- pos = mPos;
- }
- str.getChars(i, i+length, mText, pos);
- mPos = pos + length;
- }
-
- private void append(char[] buf, int i, final int length) throws IOException {
- if (length > BUFFER_LEN) {
- final int end = i + length;
- while (i < end) {
- int next = i + BUFFER_LEN;
- append(buf, i, next<end ? BUFFER_LEN : (end-i));
- i = next;
- }
- return;
- }
- int pos = mPos;
- if ((pos+length) > BUFFER_LEN) {
- flush();
- pos = mPos;
- }
- System.arraycopy(buf, i, mText, pos, length);
- mPos = pos + length;
- }
-
- private void append(String str) throws IOException {
- append(str, 0, str.length());
- }
-
- private void escapeAndAppendString(final String string) throws IOException {
- final int N = string.length();
- final char NE = (char)ESCAPE_TABLE.length;
- final String[] escapes = ESCAPE_TABLE;
- int lastPos = 0;
- int pos;
- for (pos=0; pos<N; pos++) {
- char c = string.charAt(pos);
- if (c >= NE) continue;
- String escape = escapes[c];
- if (escape == null) continue;
- if (lastPos < pos) append(string, lastPos, pos-lastPos);
- lastPos = pos + 1;
- append(escape);
- }
- if (lastPos < pos) append(string, lastPos, pos-lastPos);
- }
-
- private void escapeAndAppendString(char[] buf, int start, int len) throws IOException {
- final char NE = (char)ESCAPE_TABLE.length;
- final String[] escapes = ESCAPE_TABLE;
- int end = start+len;
- int lastPos = start;
- int pos;
- for (pos=start; pos<end; pos++) {
- char c = buf[pos];
- if (c >= NE) continue;
- String escape = escapes[c];
- if (escape == null) continue;
- if (lastPos < pos) append(buf, lastPos, pos-lastPos);
- lastPos = pos + 1;
- append(escape);
- }
- if (lastPos < pos) append(buf, lastPos, pos-lastPos);
- }
-
- public XmlSerializer attribute(String namespace, String name, String value) throws IOException,
- IllegalArgumentException, IllegalStateException {
- append(' ');
- if (namespace != null) {
- append(namespace);
- append(':');
- }
- append(name);
- append("=\"");
-
- escapeAndAppendString(value);
- append('"');
- return this;
- }
-
- public void cdsect(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void comment(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void docdecl(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void endDocument() throws IOException, IllegalArgumentException, IllegalStateException {
- flush();
- }
-
- public XmlSerializer endTag(String namespace, String name) throws IOException,
- IllegalArgumentException, IllegalStateException {
- if (mInTag) {
- append(" />\n");
- } else {
- append("</");
- if (namespace != null) {
- append(namespace);
- append(':');
- }
- append(name);
- append(">\n");
- }
- mInTag = false;
- return this;
- }
-
- public void entityRef(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- private void flushBytes() throws IOException {
- int position;
- if ((position = mBytes.position()) > 0) {
- mBytes.flip();
- mOutputStream.write(mBytes.array(), 0, position);
- mBytes.clear();
- }
- }
-
- public void flush() throws IOException {
- //Log.i("PackageManager", "flush mPos=" + mPos);
- if (mPos > 0) {
- if (mOutputStream != null) {
- CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos);
- CoderResult result = mCharset.encode(charBuffer, mBytes, true);
- while (true) {
- if (result.isError()) {
- throw new IOException(result.toString());
- } else if (result.isOverflow()) {
- flushBytes();
- result = mCharset.encode(charBuffer, mBytes, true);
- continue;
- }
- break;
- }
- flushBytes();
- mOutputStream.flush();
- } else {
- mWriter.write(mText, 0, mPos);
- mWriter.flush();
- }
- mPos = 0;
- }
- }
-
- public int getDepth() {
- throw new UnsupportedOperationException();
- }
-
- public boolean getFeature(String name) {
- throw new UnsupportedOperationException();
- }
-
- public String getName() {
- throw new UnsupportedOperationException();
- }
-
- public String getNamespace() {
- throw new UnsupportedOperationException();
- }
-
- public String getPrefix(String namespace, boolean generatePrefix)
- throws IllegalArgumentException {
- throw new UnsupportedOperationException();
- }
-
- public Object getProperty(String name) {
- throw new UnsupportedOperationException();
- }
-
- public void ignorableWhitespace(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void processingInstruction(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void setFeature(String name, boolean state) throws IllegalArgumentException,
- IllegalStateException {
- if (name.equals("http://xmlpull.org/v1/doc/features.html#indent-output")) {
- return;
- }
- throw new UnsupportedOperationException();
- }
-
- public void setOutput(OutputStream os, String encoding) throws IOException,
- IllegalArgumentException, IllegalStateException {
- if (os == null)
- throw new IllegalArgumentException();
- if (true) {
- try {
- mCharset = Charset.forName(encoding).newEncoder();
- } catch (IllegalCharsetNameException e) {
- throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
- encoding).initCause(e));
- } catch (UnsupportedCharsetException e) {
- throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
- encoding).initCause(e));
- }
- mOutputStream = os;
- } else {
- setOutput(
- encoding == null
- ? new OutputStreamWriter(os)
- : new OutputStreamWriter(os, encoding));
- }
- }
-
- public void setOutput(Writer writer) throws IOException, IllegalArgumentException,
- IllegalStateException {
- mWriter = writer;
- }
-
- public void setPrefix(String prefix, String namespace) throws IOException,
- IllegalArgumentException, IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void setProperty(String name, Object value) throws IllegalArgumentException,
- IllegalStateException {
- throw new UnsupportedOperationException();
- }
-
- public void startDocument(String encoding, Boolean standalone) throws IOException,
- IllegalArgumentException, IllegalStateException {
- append("<?xml version='1.0' encoding='utf-8' standalone='"
- + (standalone ? "yes" : "no") + "' ?>\n");
- }
-
- public XmlSerializer startTag(String namespace, String name) throws IOException,
- IllegalArgumentException, IllegalStateException {
- if (mInTag) {
- append(">\n");
- }
- append('<');
- if (namespace != null) {
- append(namespace);
- append(':');
- }
- append(name);
- mInTag = true;
- return this;
- }
-
- public XmlSerializer text(char[] buf, int start, int len) throws IOException,
- IllegalArgumentException, IllegalStateException {
- if (mInTag) {
- append(">");
- mInTag = false;
- }
- escapeAndAppendString(buf, start, len);
- return this;
- }
-
- public XmlSerializer text(String text) throws IOException, IllegalArgumentException,
- IllegalStateException {
- if (mInTag) {
- append(">");
- mInTag = false;
- }
- escapeAndAppendString(text);
- return this;
- }
-
-}
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
deleted file mode 100644
index 948e313..0000000
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ /dev/null
@@ -1,796 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import android.util.Xml;
-
-/** {@hide} */
-public class XmlUtils
-{
-
- public static void skipCurrentTag(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- }
- }
-
- public static final int
- convertValueToList(CharSequence value, String[] options, int defaultValue)
- {
- if (null != value) {
- for (int i = 0; i < options.length; i++) {
- if (value.equals(options[i]))
- return i;
- }
- }
-
- return defaultValue;
- }
-
- public static final boolean
- convertValueToBoolean(CharSequence value, boolean defaultValue)
- {
- boolean result = false;
-
- if (null == value)
- return defaultValue;
-
- if (value.equals("1")
- || value.equals("true")
- || value.equals("TRUE"))
- result = true;
-
- return result;
- }
-
- public static final int
- convertValueToInt(CharSequence charSeq, int defaultValue)
- {
- if (null == charSeq)
- return defaultValue;
-
- String nm = charSeq.toString();
-
- // XXX This code is copied from Integer.decode() so we don't
- // have to instantiate an Integer!
-
- int value;
- int sign = 1;
- int index = 0;
- int len = nm.length();
- int base = 10;
-
- if ('-' == nm.charAt(0)) {
- sign = -1;
- index++;
- }
-
- if ('0' == nm.charAt(index)) {
- // Quick check for a zero by itself
- if (index == (len - 1))
- return 0;
-
- char c = nm.charAt(index + 1);
-
- if ('x' == c || 'X' == c) {
- index += 2;
- base = 16;
- } else {
- index++;
- base = 8;
- }
- }
- else if ('#' == nm.charAt(index))
- {
- index++;
- base = 16;
- }
-
- return Integer.parseInt(nm.substring(index), base) * sign;
- }
-
- public static final int
- convertValueToUnsignedInt(String value, int defaultValue)
- {
- if (null == value)
- return defaultValue;
-
- return parseUnsignedIntAttribute(value);
- }
-
- public static final int
- parseUnsignedIntAttribute(CharSequence charSeq)
- {
- String value = charSeq.toString();
-
- long bits;
- int index = 0;
- int len = value.length();
- int base = 10;
-
- if ('0' == value.charAt(index)) {
- // Quick check for zero by itself
- if (index == (len - 1))
- return 0;
-
- char c = value.charAt(index + 1);
-
- if ('x' == c || 'X' == c) { // check for hex
- index += 2;
- base = 16;
- } else { // check for octal
- index++;
- base = 8;
- }
- } else if ('#' == value.charAt(index)) {
- index++;
- base = 16;
- }
-
- return (int) Long.parseLong(value.substring(index), base);
- }
-
- /**
- * Flatten a Map into an output stream as XML. The map can later be
- * read back with readMapXml().
- *
- * @param val The map to be flattened.
- * @param out Where to write the XML data.
- *
- * @see #writeMapXml(Map, String, XmlSerializer)
- * @see #writeListXml
- * @see #writeValueXml
- * @see #readMapXml
- */
- public static final void writeMapXml(Map val, OutputStream out)
- throws XmlPullParserException, java.io.IOException {
- XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(out, "utf-8");
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- writeMapXml(val, null, serializer);
- serializer.endDocument();
- }
-
- /**
- * Flatten a List into an output stream as XML. The list can later be
- * read back with readListXml().
- *
- * @param val The list to be flattened.
- * @param out Where to write the XML data.
- *
- * @see #writeListXml(List, String, XmlSerializer)
- * @see #writeMapXml
- * @see #writeValueXml
- * @see #readListXml
- */
- public static final void writeListXml(List val, OutputStream out)
- throws XmlPullParserException, java.io.IOException
- {
- XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(out, "utf-8");
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- writeListXml(val, null, serializer);
- serializer.endDocument();
- }
-
- /**
- * Flatten a Map into an XmlSerializer. The map can later be read back
- * with readThisMapXml().
- *
- * @param val The map to be flattened.
- * @param name Name attribute to include with this list's tag, or null for
- * none.
- * @param out XmlSerializer to write the map into.
- *
- * @see #writeMapXml(Map, OutputStream)
- * @see #writeListXml
- * @see #writeValueXml
- * @see #readMapXml
- */
- public static final void writeMapXml(Map val, String name, XmlSerializer out)
- throws XmlPullParserException, java.io.IOException
- {
- if (val == null) {
- out.startTag(null, "null");
- out.endTag(null, "null");
- return;
- }
-
- Set s = val.entrySet();
- Iterator i = s.iterator();
-
- out.startTag(null, "map");
- if (name != null) {
- out.attribute(null, "name", name);
- }
-
- while (i.hasNext()) {
- Map.Entry e = (Map.Entry)i.next();
- writeValueXml(e.getValue(), (String)e.getKey(), out);
- }
-
- out.endTag(null, "map");
- }
-
- /**
- * Flatten a List into an XmlSerializer. The list can later be read back
- * with readThisListXml().
- *
- * @param val The list to be flattened.
- * @param name Name attribute to include with this list's tag, or null for
- * none.
- * @param out XmlSerializer to write the list into.
- *
- * @see #writeListXml(List, OutputStream)
- * @see #writeMapXml
- * @see #writeValueXml
- * @see #readListXml
- */
- public static final void writeListXml(List val, String name, XmlSerializer out)
- throws XmlPullParserException, java.io.IOException
- {
- if (val == null) {
- out.startTag(null, "null");
- out.endTag(null, "null");
- return;
- }
-
- out.startTag(null, "list");
- if (name != null) {
- out.attribute(null, "name", name);
- }
-
- int N = val.size();
- int i=0;
- while (i < N) {
- writeValueXml(val.get(i), null, out);
- i++;
- }
-
- out.endTag(null, "list");
- }
-
- /**
- * Flatten a byte[] into an XmlSerializer. The list can later be read back
- * with readThisByteArrayXml().
- *
- * @param val The byte array to be flattened.
- * @param name Name attribute to include with this array's tag, or null for
- * none.
- * @param out XmlSerializer to write the array into.
- *
- * @see #writeMapXml
- * @see #writeValueXml
- */
- public static final void writeByteArrayXml(byte[] val, String name,
- XmlSerializer out)
- throws XmlPullParserException, java.io.IOException {
-
- if (val == null) {
- out.startTag(null, "null");
- out.endTag(null, "null");
- return;
- }
-
- out.startTag(null, "byte-array");
- if (name != null) {
- out.attribute(null, "name", name);
- }
-
- final int N = val.length;
- out.attribute(null, "num", Integer.toString(N));
-
- StringBuilder sb = new StringBuilder(val.length*2);
- for (int i=0; i<N; i++) {
- int b = val[i];
- int h = b>>4;
- sb.append(h >= 10 ? ('a'+h-10) : ('0'+h));
- h = b&0xff;
- sb.append(h >= 10 ? ('a'+h-10) : ('0'+h));
- }
-
- out.text(sb.toString());
-
- out.endTag(null, "byte-array");
- }
-
- /**
- * Flatten an int[] into an XmlSerializer. The list can later be read back
- * with readThisIntArrayXml().
- *
- * @param val The int array to be flattened.
- * @param name Name attribute to include with this array's tag, or null for
- * none.
- * @param out XmlSerializer to write the array into.
- *
- * @see #writeMapXml
- * @see #writeValueXml
- * @see #readThisIntArrayXml
- */
- public static final void writeIntArrayXml(int[] val, String name,
- XmlSerializer out)
- throws XmlPullParserException, java.io.IOException {
-
- if (val == null) {
- out.startTag(null, "null");
- out.endTag(null, "null");
- return;
- }
-
- out.startTag(null, "int-array");
- if (name != null) {
- out.attribute(null, "name", name);
- }
-
- final int N = val.length;
- out.attribute(null, "num", Integer.toString(N));
-
- for (int i=0; i<N; i++) {
- out.startTag(null, "item");
- out.attribute(null, "value", Integer.toString(val[i]));
- out.endTag(null, "item");
- }
-
- out.endTag(null, "int-array");
- }
-
- /**
- * Flatten an object's value into an XmlSerializer. The value can later
- * be read back with readThisValueXml().
- *
- * Currently supported value types are: null, String, Integer, Long,
- * Float, Double Boolean, Map, List.
- *
- * @param v The object to be flattened.
- * @param name Name attribute to include with this value's tag, or null
- * for none.
- * @param out XmlSerializer to write the object into.
- *
- * @see #writeMapXml
- * @see #writeListXml
- * @see #readValueXml
- */
- public static final void writeValueXml(Object v, String name, XmlSerializer out)
- throws XmlPullParserException, java.io.IOException
- {
- String typeStr;
- if (v == null) {
- out.startTag(null, "null");
- if (name != null) {
- out.attribute(null, "name", name);
- }
- out.endTag(null, "null");
- return;
- } else if (v instanceof String) {
- out.startTag(null, "string");
- if (name != null) {
- out.attribute(null, "name", name);
- }
- out.text(v.toString());
- out.endTag(null, "string");
- return;
- } else if (v instanceof Integer) {
- typeStr = "int";
- } else if (v instanceof Long) {
- typeStr = "long";
- } else if (v instanceof Float) {
- typeStr = "float";
- } else if (v instanceof Double) {
- typeStr = "double";
- } else if (v instanceof Boolean) {
- typeStr = "boolean";
- } else if (v instanceof byte[]) {
- writeByteArrayXml((byte[])v, name, out);
- return;
- } else if (v instanceof int[]) {
- writeIntArrayXml((int[])v, name, out);
- return;
- } else if (v instanceof Map) {
- writeMapXml((Map)v, name, out);
- return;
- } else if (v instanceof List) {
- writeListXml((List)v, name, out);
- return;
- } else if (v instanceof CharSequence) {
- // XXX This is to allow us to at least write something if
- // we encounter styled text... but it means we will drop all
- // of the styling information. :(
- out.startTag(null, "string");
- if (name != null) {
- out.attribute(null, "name", name);
- }
- out.text(v.toString());
- out.endTag(null, "string");
- return;
- } else {
- throw new RuntimeException("writeValueXml: unable to write value " + v);
- }
-
- out.startTag(null, typeStr);
- if (name != null) {
- out.attribute(null, "name", name);
- }
- out.attribute(null, "value", v.toString());
- out.endTag(null, typeStr);
- }
-
- /**
- * Read a HashMap from an InputStream containing XML. The stream can
- * previously have been written by writeMapXml().
- *
- * @param in The InputStream from which to read.
- *
- * @return HashMap The resulting map.
- *
- * @see #readListXml
- * @see #readValueXml
- * @see #readThisMapXml
- * #see #writeMapXml
- */
- public static final HashMap readMapXml(InputStream in)
- throws XmlPullParserException, java.io.IOException
- {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, null);
- return (HashMap)readValueXml(parser, new String[1]);
- }
-
- /**
- * Read an ArrayList from an InputStream containing XML. The stream can
- * previously have been written by writeListXml().
- *
- * @param in The InputStream from which to read.
- *
- * @return HashMap The resulting list.
- *
- * @see #readMapXml
- * @see #readValueXml
- * @see #readThisListXml
- * @see #writeListXml
- */
- public static final ArrayList readListXml(InputStream in)
- throws XmlPullParserException, java.io.IOException
- {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, null);
- return (ArrayList)readValueXml(parser, new String[1]);
- }
-
- /**
- * Read a HashMap object from an XmlPullParser. The XML data could
- * previously have been generated by writeMapXml(). The XmlPullParser
- * must be positioned <em>after</em> the tag that begins the map.
- *
- * @param parser The XmlPullParser from which to read the map data.
- * @param endTag Name of the tag that will end the map, usually "map".
- * @param name An array of one string, used to return the name attribute
- * of the map's tag.
- *
- * @return HashMap The newly generated map.
- *
- * @see #readMapXml
- */
- public static final HashMap readThisMapXml(XmlPullParser parser, String endTag, String[] name)
- throws XmlPullParserException, java.io.IOException
- {
- HashMap map = new HashMap();
-
- int eventType = parser.getEventType();
- do {
- if (eventType == parser.START_TAG) {
- Object val = readThisValueXml(parser, name);
- if (name[0] != null) {
- //System.out.println("Adding to map: " + name + " -> " + val);
- map.put(name[0], val);
- } else {
- throw new XmlPullParserException(
- "Map value without name attribute: " + parser.getName());
- }
- } else if (eventType == parser.END_TAG) {
- if (parser.getName().equals(endTag)) {
- return map;
- }
- throw new XmlPullParserException(
- "Expected " + endTag + " end tag at: " + parser.getName());
- }
- eventType = parser.next();
- } while (eventType != parser.END_DOCUMENT);
-
- throw new XmlPullParserException(
- "Document ended before " + endTag + " end tag");
- }
-
- /**
- * Read an ArrayList object from an XmlPullParser. The XML data could
- * previously have been generated by writeListXml(). The XmlPullParser
- * must be positioned <em>after</em> the tag that begins the list.
- *
- * @param parser The XmlPullParser from which to read the list data.
- * @param endTag Name of the tag that will end the list, usually "list".
- * @param name An array of one string, used to return the name attribute
- * of the list's tag.
- *
- * @return HashMap The newly generated list.
- *
- * @see #readListXml
- */
- public static final ArrayList readThisListXml(XmlPullParser parser, String endTag, String[] name)
- throws XmlPullParserException, java.io.IOException
- {
- ArrayList list = new ArrayList();
-
- int eventType = parser.getEventType();
- do {
- if (eventType == parser.START_TAG) {
- Object val = readThisValueXml(parser, name);
- list.add(val);
- //System.out.println("Adding to list: " + val);
- } else if (eventType == parser.END_TAG) {
- if (parser.getName().equals(endTag)) {
- return list;
- }
- throw new XmlPullParserException(
- "Expected " + endTag + " end tag at: " + parser.getName());
- }
- eventType = parser.next();
- } while (eventType != parser.END_DOCUMENT);
-
- throw new XmlPullParserException(
- "Document ended before " + endTag + " end tag");
- }
-
- /**
- * Read an int[] object from an XmlPullParser. The XML data could
- * previously have been generated by writeIntArrayXml(). The XmlPullParser
- * must be positioned <em>after</em> the tag that begins the list.
- *
- * @param parser The XmlPullParser from which to read the list data.
- * @param endTag Name of the tag that will end the list, usually "list".
- * @param name An array of one string, used to return the name attribute
- * of the list's tag.
- *
- * @return Returns a newly generated int[].
- *
- * @see #readListXml
- */
- public static final int[] readThisIntArrayXml(XmlPullParser parser,
- String endTag, String[] name)
- throws XmlPullParserException, java.io.IOException {
-
- int num;
- try {
- num = Integer.parseInt(parser.getAttributeValue(null, "num"));
- } catch (NullPointerException e) {
- throw new XmlPullParserException(
- "Need num attribute in byte-array");
- } catch (NumberFormatException e) {
- throw new XmlPullParserException(
- "Not a number in num attribute in byte-array");
- }
-
- int[] array = new int[num];
- int i = 0;
-
- int eventType = parser.getEventType();
- do {
- if (eventType == parser.START_TAG) {
- if (parser.getName().equals("item")) {
- try {
- array[i] = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } catch (NullPointerException e) {
- throw new XmlPullParserException(
- "Need value attribute in item");
- } catch (NumberFormatException e) {
- throw new XmlPullParserException(
- "Not a number in value attribute in item");
- }
- } else {
- throw new XmlPullParserException(
- "Expected item tag at: " + parser.getName());
- }
- } else if (eventType == parser.END_TAG) {
- if (parser.getName().equals(endTag)) {
- return array;
- } else if (parser.getName().equals("item")) {
- i++;
- } else {
- throw new XmlPullParserException(
- "Expected " + endTag + " end tag at: "
- + parser.getName());
- }
- }
- eventType = parser.next();
- } while (eventType != parser.END_DOCUMENT);
-
- throw new XmlPullParserException(
- "Document ended before " + endTag + " end tag");
- }
-
- /**
- * Read a flattened object from an XmlPullParser. The XML data could
- * previously have been written with writeMapXml(), writeListXml(), or
- * writeValueXml(). The XmlPullParser must be positioned <em>at</em> the
- * tag that defines the value.
- *
- * @param parser The XmlPullParser from which to read the object.
- * @param name An array of one string, used to return the name attribute
- * of the value's tag.
- *
- * @return Object The newly generated value object.
- *
- * @see #readMapXml
- * @see #readListXml
- * @see #writeValueXml
- */
- public static final Object readValueXml(XmlPullParser parser, String[] name)
- throws XmlPullParserException, java.io.IOException
- {
- int eventType = parser.getEventType();
- do {
- if (eventType == parser.START_TAG) {
- return readThisValueXml(parser, name);
- } else if (eventType == parser.END_TAG) {
- throw new XmlPullParserException(
- "Unexpected end tag at: " + parser.getName());
- } else if (eventType == parser.TEXT) {
- throw new XmlPullParserException(
- "Unexpected text: " + parser.getText());
- }
- eventType = parser.next();
- } while (eventType != parser.END_DOCUMENT);
-
- throw new XmlPullParserException(
- "Unexpected end of document");
- }
-
- private static final Object readThisValueXml(XmlPullParser parser, String[] name)
- throws XmlPullParserException, java.io.IOException
- {
- final String valueName = parser.getAttributeValue(null, "name");
- final String tagName = parser.getName();
-
- //System.out.println("Reading this value tag: " + tagName + ", name=" + valueName);
-
- Object res;
-
- if (tagName.equals("null")) {
- res = null;
- } else if (tagName.equals("string")) {
- String value = "";
- int eventType;
- while ((eventType = parser.next()) != parser.END_DOCUMENT) {
- if (eventType == parser.END_TAG) {
- if (parser.getName().equals("string")) {
- name[0] = valueName;
- //System.out.println("Returning value for " + valueName + ": " + value);
- return value;
- }
- throw new XmlPullParserException(
- "Unexpected end tag in <string>: " + parser.getName());
- } else if (eventType == parser.TEXT) {
- value += parser.getText();
- } else if (eventType == parser.START_TAG) {
- throw new XmlPullParserException(
- "Unexpected start tag in <string>: " + parser.getName());
- }
- }
- throw new XmlPullParserException(
- "Unexpected end of document in <string>");
- } else if (tagName.equals("int")) {
- res = Integer.parseInt(parser.getAttributeValue(null, "value"));
- } else if (tagName.equals("long")) {
- res = Long.valueOf(parser.getAttributeValue(null, "value"));
- } else if (tagName.equals("float")) {
- res = new Float(parser.getAttributeValue(null, "value"));
- } else if (tagName.equals("double")) {
- res = new Double(parser.getAttributeValue(null, "value"));
- } else if (tagName.equals("boolean")) {
- res = Boolean.valueOf(parser.getAttributeValue(null, "value"));
- } else if (tagName.equals("int-array")) {
- parser.next();
- res = readThisIntArrayXml(parser, "int-array", name);
- name[0] = valueName;
- //System.out.println("Returning value for " + valueName + ": " + res);
- return res;
- } else if (tagName.equals("map")) {
- parser.next();
- res = readThisMapXml(parser, "map", name);
- name[0] = valueName;
- //System.out.println("Returning value for " + valueName + ": " + res);
- return res;
- } else if (tagName.equals("list")) {
- parser.next();
- res = readThisListXml(parser, "list", name);
- name[0] = valueName;
- //System.out.println("Returning value for " + valueName + ": " + res);
- return res;
- } else {
- throw new XmlPullParserException(
- "Unknown tag: " + tagName);
- }
-
- // Skip through to end tag.
- int eventType;
- while ((eventType = parser.next()) != parser.END_DOCUMENT) {
- if (eventType == parser.END_TAG) {
- if (parser.getName().equals(tagName)) {
- name[0] = valueName;
- //System.out.println("Returning value for " + valueName + ": " + res);
- return res;
- }
- throw new XmlPullParserException(
- "Unexpected end tag in <" + tagName + ">: " + parser.getName());
- } else if (eventType == parser.TEXT) {
- throw new XmlPullParserException(
- "Unexpected text in <" + tagName + ">: " + parser.getName());
- } else if (eventType == parser.START_TAG) {
- throw new XmlPullParserException(
- "Unexpected start tag in <" + tagName + ">: " + parser.getName());
- }
- }
- throw new XmlPullParserException(
- "Unexpected end of document in <" + tagName + ">");
- }
-
- public static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException
- {
- int type;
- while ((type=parser.next()) != parser.START_TAG
- && type != parser.END_DOCUMENT) {
- ;
- }
-
- if (type != parser.START_TAG) {
- throw new XmlPullParserException("No start tag found");
- }
-
- if (!parser.getName().equals(firstElementName)) {
- throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
- ", expected " + firstElementName);
- }
- }
-
- public static final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException
- {
- int type;
- while ((type=parser.next()) != parser.START_TAG
- && type != parser.END_DOCUMENT) {
- ;
- }
- }
-}
diff --git a/core/java/com/android/internal/widget/VerticalTextSpinner.java b/core/java/com/android/internal/widget/VerticalTextSpinner.java
deleted file mode 100644
index 50c528c..0000000
--- a/core/java/com/android/internal/widget/VerticalTextSpinner.java
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.text.TextPaint;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-
-
-public class VerticalTextSpinner extends View {
-
- private static final int SELECTOR_ARROW_HEIGHT = 15;
-
- private static final int TEXT_SPACING = 18;
- private static final int TEXT_MARGIN_RIGHT = 25;
- private static final int TEXT_SIZE = 22;
-
- /* Keep the calculations as this is really a for loop from
- * -2 to 2 but precalculated so we don't have to do in the onDraw.
- */
- private static final int TEXT1_Y = (TEXT_SIZE * (-2 + 2)) + (TEXT_SPACING * (-2 + 1));
- private static final int TEXT2_Y = (TEXT_SIZE * (-1 + 2)) + (TEXT_SPACING * (-1 + 1));
- private static final int TEXT3_Y = (TEXT_SIZE * (0 + 2)) + (TEXT_SPACING * (0 + 1));
- private static final int TEXT4_Y = (TEXT_SIZE * (1 + 2)) + (TEXT_SPACING * (1 + 1));
- private static final int TEXT5_Y = (TEXT_SIZE * (2 + 2)) + (TEXT_SPACING * (2 + 1));
-
- private static final int SCROLL_MODE_NONE = 0;
- private static final int SCROLL_MODE_UP = 1;
- private static final int SCROLL_MODE_DOWN = 2;
-
- private static final long DEFAULT_SCROLL_INTERVAL_MS = 400;
- private static final int SCROLL_DISTANCE = TEXT_SIZE + TEXT_SPACING;
- private static final int MIN_ANIMATIONS = 4;
-
- private final Drawable mBackgroundFocused;
- private final Drawable mSelectorFocused;
- private final Drawable mSelectorNormal;
- private final int mSelectorDefaultY;
- private final int mSelectorMinY;
- private final int mSelectorMaxY;
- private final int mSelectorHeight;
- private final TextPaint mTextPaintDark;
- private final TextPaint mTextPaintLight;
-
- private int mSelectorY;
- private Drawable mSelector;
- private int mDownY;
- private boolean isDraggingSelector;
- private int mScrollMode;
- private long mScrollInterval;
- private boolean mIsAnimationRunning;
- private boolean mStopAnimation;
- private boolean mWrapAround = true;
-
- private int mTotalAnimatedDistance;
- private int mNumberOfAnimations;
- private long mDelayBetweenAnimations;
- private int mDistanceOfEachAnimation;
-
- private String[] mTextList;
- private int mCurrentSelectedPos;
- private OnChangedListener mListener;
-
- private String mText1;
- private String mText2;
- private String mText3;
- private String mText4;
- private String mText5;
-
- public interface OnChangedListener {
- void onChanged(
- VerticalTextSpinner spinner, int oldPos, int newPos, String[] items);
- }
-
- public VerticalTextSpinner(Context context) {
- this(context, null);
- }
-
- public VerticalTextSpinner(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public VerticalTextSpinner(Context context, AttributeSet attrs,
- int defStyle) {
- super(context, attrs, defStyle);
-
- mBackgroundFocused = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_background);
- mSelectorFocused = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_selected);
- mSelectorNormal = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_unselected);
-
- mSelectorHeight = mSelectorFocused.getIntrinsicHeight();
- mSelectorDefaultY = (mBackgroundFocused.getIntrinsicHeight() - mSelectorHeight) / 2;
- mSelectorMinY = 0;
- mSelectorMaxY = mBackgroundFocused.getIntrinsicHeight() - mSelectorHeight;
-
- mSelector = mSelectorNormal;
- mSelectorY = mSelectorDefaultY;
-
- mTextPaintDark = new TextPaint(Paint.ANTI_ALIAS_FLAG);
- mTextPaintDark.setTextSize(TEXT_SIZE);
- mTextPaintDark.setColor(context.getResources().getColor(com.android.internal.R.color.primary_text_light));
-
- mTextPaintLight = new TextPaint(Paint.ANTI_ALIAS_FLAG);
- mTextPaintLight.setTextSize(TEXT_SIZE);
- mTextPaintLight.setColor(context.getResources().getColor(com.android.internal.R.color.secondary_text_dark));
-
- mScrollMode = SCROLL_MODE_NONE;
- mScrollInterval = DEFAULT_SCROLL_INTERVAL_MS;
- calculateAnimationValues();
- }
-
- public void setOnChangeListener(OnChangedListener listener) {
- mListener = listener;
- }
-
- public void setItems(String[] textList) {
- mTextList = textList;
- calculateTextPositions();
- }
-
- public void setSelectedPos(int selectedPos) {
- mCurrentSelectedPos = selectedPos;
- calculateTextPositions();
- postInvalidate();
- }
-
- public void setScrollInterval(long interval) {
- mScrollInterval = interval;
- calculateAnimationValues();
- }
-
- public void setWrapAround(boolean wrap) {
- mWrapAround = wrap;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
-
- /* This is a bit confusing, when we get the key event
- * DPAD_DOWN we actually roll the spinner up. When the
- * key event is DPAD_UP we roll the spinner down.
- */
- if ((keyCode == KeyEvent.KEYCODE_DPAD_UP) && canScrollDown()) {
- mScrollMode = SCROLL_MODE_DOWN;
- scroll();
- mStopAnimation = true;
- return true;
- } else if ((keyCode == KeyEvent.KEYCODE_DPAD_DOWN) && canScrollUp()) {
- mScrollMode = SCROLL_MODE_UP;
- scroll();
- mStopAnimation = true;
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- private boolean canScrollDown() {
- return (mCurrentSelectedPos > 0) || mWrapAround;
- }
-
- private boolean canScrollUp() {
- return ((mCurrentSelectedPos < (mTextList.length - 1)) || mWrapAround);
- }
-
- @Override
- protected void onFocusChanged(boolean gainFocus, int direction,
- Rect previouslyFocusedRect) {
- if (gainFocus) {
- setBackgroundDrawable(mBackgroundFocused);
- mSelector = mSelectorFocused;
- } else {
- setBackgroundDrawable(null);
- mSelector = mSelectorNormal;
- mSelectorY = mSelectorDefaultY;
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- final int action = event.getAction();
- final int y = (int) event.getY();
-
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- requestFocus();
- mDownY = y;
- isDraggingSelector = (y >= mSelectorY) && (y <= (mSelectorY + mSelector.getIntrinsicHeight()));
- break;
-
- case MotionEvent.ACTION_MOVE:
- if (isDraggingSelector) {
- int top = mSelectorDefaultY + (y - mDownY);
- if (top <= mSelectorMinY && canScrollDown()) {
- mSelectorY = mSelectorMinY;
- mStopAnimation = false;
- if (mScrollMode != SCROLL_MODE_DOWN) {
- mScrollMode = SCROLL_MODE_DOWN;
- scroll();
- }
- } else if (top >= mSelectorMaxY && canScrollUp()) {
- mSelectorY = mSelectorMaxY;
- mStopAnimation = false;
- if (mScrollMode != SCROLL_MODE_UP) {
- mScrollMode = SCROLL_MODE_UP;
- scroll();
- }
- } else {
- mSelectorY = top;
- mStopAnimation = true;
- }
- }
- break;
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- default:
- mSelectorY = mSelectorDefaultY;
- mStopAnimation = true;
- invalidate();
- break;
- }
- return true;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
-
- /* The bounds of the selector */
- final int selectorLeft = 0;
- final int selectorTop = mSelectorY;
- final int selectorRight = mMeasuredWidth;
- final int selectorBottom = mSelectorY + mSelectorHeight;
-
- /* Draw the selector */
- mSelector.setBounds(selectorLeft, selectorTop, selectorRight, selectorBottom);
- mSelector.draw(canvas);
-
- if (mTextList == null) {
-
- /* We're not setup with values so don't draw anything else */
- return;
- }
-
- final TextPaint textPaintDark = mTextPaintDark;
- if (hasFocus()) {
-
- /* The bounds of the top area where the text should be light */
- final int topLeft = 0;
- final int topTop = 0;
- final int topRight = selectorRight;
- final int topBottom = selectorTop + SELECTOR_ARROW_HEIGHT;
-
- /* Assign a bunch of local finals for performance */
- final String text1 = mText1;
- final String text2 = mText2;
- final String text3 = mText3;
- final String text4 = mText4;
- final String text5 = mText5;
- final TextPaint textPaintLight = mTextPaintLight;
-
- /*
- * Draw the 1st, 2nd and 3rd item in light only, clip it so it only
- * draws in the area above the selector
- */
- canvas.save();
- canvas.clipRect(topLeft, topTop, topRight, topBottom);
- drawText(canvas, text1, TEXT1_Y
- + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text2, TEXT2_Y
- + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text3,
- TEXT3_Y + mTotalAnimatedDistance, textPaintLight);
- canvas.restore();
-
- /*
- * Draw the 2nd, 3rd and 4th clipped to the selector bounds in dark
- * paint
- */
- canvas.save();
- canvas.clipRect(selectorLeft, selectorTop + SELECTOR_ARROW_HEIGHT,
- selectorRight, selectorBottom - SELECTOR_ARROW_HEIGHT);
- drawText(canvas, text2, TEXT2_Y
- + mTotalAnimatedDistance, textPaintDark);
- drawText(canvas, text3,
- TEXT3_Y + mTotalAnimatedDistance, textPaintDark);
- drawText(canvas, text4,
- TEXT4_Y + mTotalAnimatedDistance, textPaintDark);
- canvas.restore();
-
- /* The bounds of the bottom area where the text should be light */
- final int bottomLeft = 0;
- final int bottomTop = selectorBottom - SELECTOR_ARROW_HEIGHT;
- final int bottomRight = selectorRight;
- final int bottomBottom = mMeasuredHeight;
-
- /*
- * Draw the 3rd, 4th and 5th in white text, clip it so it only draws
- * in the area below the selector.
- */
- canvas.save();
- canvas.clipRect(bottomLeft, bottomTop, bottomRight, bottomBottom);
- drawText(canvas, text3,
- TEXT3_Y + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text4,
- TEXT4_Y + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text5,
- TEXT5_Y + mTotalAnimatedDistance, textPaintLight);
- canvas.restore();
-
- } else {
- drawText(canvas, mText3, TEXT3_Y, textPaintDark);
- }
- if (mIsAnimationRunning) {
- if ((Math.abs(mTotalAnimatedDistance) + mDistanceOfEachAnimation) > SCROLL_DISTANCE) {
- mTotalAnimatedDistance = 0;
- if (mScrollMode == SCROLL_MODE_UP) {
- int oldPos = mCurrentSelectedPos;
- int newPos = getNewIndex(1);
- if (newPos >= 0) {
- mCurrentSelectedPos = newPos;
- if (mListener != null) {
- mListener.onChanged(this, oldPos, mCurrentSelectedPos, mTextList);
- }
- }
- if (newPos < 0 || ((newPos >= mTextList.length - 1) && !mWrapAround)) {
- mStopAnimation = true;
- }
- calculateTextPositions();
- } else if (mScrollMode == SCROLL_MODE_DOWN) {
- int oldPos = mCurrentSelectedPos;
- int newPos = getNewIndex(-1);
- if (newPos >= 0) {
- mCurrentSelectedPos = newPos;
- if (mListener != null) {
- mListener.onChanged(this, oldPos, mCurrentSelectedPos, mTextList);
- }
- }
- if (newPos < 0 || (newPos == 0 && !mWrapAround)) {
- mStopAnimation = true;
- }
- calculateTextPositions();
- }
- if (mStopAnimation) {
- final int previousScrollMode = mScrollMode;
-
- /* No longer scrolling, we wait till the current animation
- * completes then we stop.
- */
- mIsAnimationRunning = false;
- mStopAnimation = false;
- mScrollMode = SCROLL_MODE_NONE;
-
- /* If the current selected item is an empty string
- * scroll past it.
- */
- if ("".equals(mTextList[mCurrentSelectedPos])) {
- mScrollMode = previousScrollMode;
- scroll();
- mStopAnimation = true;
- }
- }
- } else {
- if (mScrollMode == SCROLL_MODE_UP) {
- mTotalAnimatedDistance -= mDistanceOfEachAnimation;
- } else if (mScrollMode == SCROLL_MODE_DOWN) {
- mTotalAnimatedDistance += mDistanceOfEachAnimation;
- }
- }
- if (mDelayBetweenAnimations > 0) {
- postInvalidateDelayed(mDelayBetweenAnimations);
- } else {
- invalidate();
- }
- }
- }
-
- /**
- * Called every time the text items or current position
- * changes. We calculate store we don't have to calculate
- * onDraw.
- */
- private void calculateTextPositions() {
- mText1 = getTextToDraw(-2);
- mText2 = getTextToDraw(-1);
- mText3 = getTextToDraw(0);
- mText4 = getTextToDraw(1);
- mText5 = getTextToDraw(2);
- }
-
- private String getTextToDraw(int offset) {
- int index = getNewIndex(offset);
- if (index < 0) {
- return "";
- }
- return mTextList[index];
- }
-
- private int getNewIndex(int offset) {
- int index = mCurrentSelectedPos + offset;
- if (index < 0) {
- if (mWrapAround) {
- index += mTextList.length;
- } else {
- return -1;
- }
- } else if (index >= mTextList.length) {
- if (mWrapAround) {
- index -= mTextList.length;
- } else {
- return -1;
- }
- }
- return index;
- }
-
- private void scroll() {
- if (mIsAnimationRunning) {
- return;
- }
- mTotalAnimatedDistance = 0;
- mIsAnimationRunning = true;
- invalidate();
- }
-
- private void calculateAnimationValues() {
- mNumberOfAnimations = (int) mScrollInterval / SCROLL_DISTANCE;
- if (mNumberOfAnimations < MIN_ANIMATIONS) {
- mNumberOfAnimations = MIN_ANIMATIONS;
- mDistanceOfEachAnimation = SCROLL_DISTANCE / mNumberOfAnimations;
- mDelayBetweenAnimations = 0;
- } else {
- mDistanceOfEachAnimation = SCROLL_DISTANCE / mNumberOfAnimations;
- mDelayBetweenAnimations = mScrollInterval / mNumberOfAnimations;
- }
- }
-
- private void drawText(Canvas canvas, String text, int y, TextPaint paint) {
- int width = (int) paint.measureText(text);
- int x = getMeasuredWidth() - width - TEXT_MARGIN_RIGHT;
- canvas.drawText(text, x, y, paint);
- }
-
- public int getCurrentSelectedPos() {
- return mCurrentSelectedPos;
- }
-}
diff --git a/core/java/com/google/android/net/NetworkStatsEntity.java b/core/java/com/google/android/net/NetworkStatsEntity.java
deleted file mode 100644
index a22fa1e..0000000
--- a/core/java/com/google/android/net/NetworkStatsEntity.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.net;
-
-import android.net.TrafficStats;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.util.EventLog;
-import org.apache.http.HttpEntity;
-import org.apache.http.entity.HttpEntityWrapper;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-
-public class NetworkStatsEntity extends HttpEntityWrapper {
-
- private static final int HTTP_STATS_EVENT = 52001;
-
- private class NetworkStatsInputStream extends FilterInputStream {
-
- public NetworkStatsInputStream(InputStream wrapped) {
- super(wrapped);
- }
-
- @Override
- public void close() throws IOException {
- try {
- super.close();
- } finally {
- long processingTime = SystemClock.elapsedRealtime() - mProcessingStartTime;
- long tx = TrafficStats.getUidTxBytes(mUid);
- long rx = TrafficStats.getUidRxBytes(mUid);
-
- EventLog.writeEvent(HTTP_STATS_EVENT, mUa, mResponseLatency, processingTime,
- tx - mStartTx, rx - mStartRx);
- }
- }
- }
-
- private final String mUa;
- private final int mUid;
- private final long mStartTx;
- private final long mStartRx;
- private final long mResponseLatency;
- private final long mProcessingStartTime;
-
- public NetworkStatsEntity(HttpEntity orig, String ua,
- int uid, long startTx, long startRx, long responseLatency,
- long processingStartTime) {
- super(orig);
- this.mUa = ua;
- this.mUid = uid;
- this.mStartTx = startTx;
- this.mStartRx = startRx;
- this.mResponseLatency = responseLatency;
- this.mProcessingStartTime = processingStartTime;
- }
-
- public static boolean shouldLogNetworkStats() {
- return "1".equals(SystemProperties.get("googlehttpclient.logstats"));
- }
-
- @Override
- public InputStream getContent() throws IOException {
- InputStream orig = super.getContent();
- return new NetworkStatsInputStream(orig);
- }
-}
diff --git a/core/java/com/google/android/net/SSLClientSessionCacheFactory.java b/core/java/com/google/android/net/SSLClientSessionCacheFactory.java
deleted file mode 100644
index 6570a9bd..0000000
--- a/core/java/com/google/android/net/SSLClientSessionCacheFactory.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.google.android.net;
-
-import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
-import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
-import android.content.Context;
-import android.provider.Settings;
-import android.util.Log;
-
-import java.io.File;
-import java.io.IOException;
-
-import com.android.internal.net.DbSSLSessionCache;
-
-/**
- * Factory that returns the appropriate implementation of a {@link SSLClientSessionCache} based
- * on gservices.
- *
- * @hide
- */
-// TODO: return a proxied implementation that is updated as the gservices value changes.
-public final class SSLClientSessionCacheFactory {
-
- private static final String TAG = "SSLClientSessionCacheFactory";
-
- public static final String DB = "db";
- public static final String FILE = "file";
-
- // utility class
- private SSLClientSessionCacheFactory() {}
-
- /**
- * Returns a new {@link SSLClientSessionCache} based on the persistent cache that's specified,
- * if any, in gservices. If no cache is specified, returns null.
- * @param context The application context used for the per-process persistent cache.
- * @return A new {@link SSLClientSessionCache}, or null if no persistent cache is configured.
- */
- public static SSLClientSessionCache getCache(Context context) {
- String type = Settings.Gservices.getString(context.getContentResolver(),
- Settings.Gservices.SSL_SESSION_CACHE);
-
- if (type != null) {
- if (DB.equals(type)) {
- return DbSSLSessionCache.getInstanceForPackage(context);
- } else if (FILE.equals(type)) {
- File dir = context.getFilesDir();
- File cacheDir = new File(dir, "sslcache");
- if (!cacheDir.exists()) {
- cacheDir.mkdir();
- }
- try {
- return FileClientSessionCache.usingDirectory(cacheDir);
- } catch (IOException ioe) {
- Log.w(TAG, "Unable to create FileClientSessionCache in " + cacheDir.getName(), ioe);
- return null;
- }
- } else {
- Log.w(TAG, "Ignoring unrecognized type: '" + type + "'");
- }
- }
- return null;
- }
-}
diff --git a/core/java/com/google/android/net/UrlRules.java b/core/java/com/google/android/net/UrlRules.java
deleted file mode 100644
index 54d139d..0000000
--- a/core/java/com/google/android/net/UrlRules.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.net;
-
-import android.content.ContentResolver;
-import android.database.Cursor;
-import android.provider.Checkin;
-import android.provider.Settings;
-import android.util.Config;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A set of rules rewriting and blocking URLs. Used to offer a point of
- * control for redirecting HTTP requests, often to the Android proxy server.
- *
- * <p>Each rule has the following format:
- *
- * <pre><em>url-prefix</em> [REWRITE <em>new-prefix</em>] [BLOCK]</pre>
- *
- * <p>Any URL which starts with <em>url-prefix</em> will trigger the rule.
- * If BLOCK is specified, requests to that URL will be blocked and fail.
- * If REWRITE is specified, the matching prefix will be removed and replaced
- * with <em>new-prefix</em>. (If both are specified, BLOCK wins.) Case is
- * insensitive for the REWRITE and BLOCK keywords, but sensitive for URLs.
- *
- * <p>In Gservices, the value of any key that starts with "url:" will be
- * interpreted as a rule. The full name of the key is unimportant (but can
- * be used to document the intent of the rule, and must be unique).
- * Example gservices keys:
- *
- * <pre>
- * url:use_proxy_for_calendar = "http://www.google.com/calendar/ REWRITE http://android.clients.google.com/proxy/calendar/"
- * url:stop_crash_reports = "http://android.clients.google.com/crash/ BLOCK"
- * url:use_ssl_for_contacts = "http://www.google.com/m8/ REWRITE https://www.google.com/m8/"
- * </pre>
- */
-public class UrlRules {
- public static final String TAG = "UrlRules";
- public static final boolean LOCAL_LOGV = Config.LOGV || false;
-
- /** Thrown when the rewrite rules can't be parsed. */
- public static class RuleFormatException extends Exception {
- public RuleFormatException(String msg) { super(msg); }
- }
-
- /** A single rule specifying actions for URLs matching a certain prefix. */
- public static class Rule implements Comparable {
- /** Name assigned to the rule (for logging and debugging). */
- public final String mName;
-
- /** Prefix required to match this rule. */
- public final String mPrefix;
-
- /** Text to replace mPrefix with (null to leave alone). */
- public final String mRewrite;
-
- /** True if matching URLs should be blocked. */
- public final boolean mBlock;
-
- /** Default rule that does nothing. */
- public static final Rule DEFAULT = new Rule();
-
- /** Parse a rewrite rule as given in a Gservices value. */
- public Rule(String name, String rule) throws RuleFormatException {
- mName = name;
- String[] words = PATTERN_SPACE_PLUS.split(rule);
- if (words.length == 0) throw new RuleFormatException("Empty rule");
-
- mPrefix = words[0];
- String rewrite = null;
- boolean block = false;
- for (int pos = 1; pos < words.length; ) {
- String word = words[pos].toLowerCase();
- if (word.equals("rewrite") && pos + 1 < words.length) {
- rewrite = words[pos + 1];
- pos += 2;
- } else if (word.equals("block")) {
- block = true;
- pos += 1;
- } else {
- throw new RuleFormatException("Illegal rule: " + rule);
- }
- // TODO: Parse timeout specifications, etc.
- }
-
- mRewrite = rewrite;
- mBlock = block;
- }
-
- /** Create the default Rule. */
- private Rule() {
- mName = "DEFAULT";
- mPrefix = "";
- mRewrite = null;
- mBlock = false;
- }
-
- /**
- * Apply the rule to a particular URL (assumed to match the rule).
- * @param url to rewrite or modify.
- * @return modified URL, or null if the URL is blocked.
- */
- public String apply(String url) {
- if (mBlock) {
- return null;
- } else if (mRewrite != null) {
- return mRewrite + url.substring(mPrefix.length());
- } else {
- return url;
- }
- }
-
- /** More generic rules are greater than more specific rules. */
- public int compareTo(Object o) {
- return ((Rule) o).mPrefix.compareTo(mPrefix);
- }
- }
-
- /** Cached rule set from Gservices. */
- private static UrlRules sCachedRules = new UrlRules(new Rule[] {});
-
- private static final Pattern PATTERN_SPACE_PLUS = Pattern.compile(" +");
- private static final Pattern RULE_PATTERN = Pattern.compile("\\W");
-
- /** Gservices digest when sCachedRules was cached. */
- private static String sCachedDigest = null;
-
- /** Currently active set of Rules. */
- private final Rule[] mRules;
-
- /** Regular expression with one capturing group for each Rule. */
- private final Pattern mPattern;
-
- /**
- * Create a rewriter from an array of Rules. Normally used only for
- * testing. Instead, use {@link #getRules} to get rules from Gservices.
- * @param rules to use.
- */
- public UrlRules(Rule[] rules) {
- // Sort the rules to put the most specific rules first.
- Arrays.sort(rules);
-
- // Construct a regular expression, escaping all the prefix strings.
- StringBuilder pattern = new StringBuilder("(");
- for (int i = 0; i < rules.length; ++i) {
- if (i > 0) pattern.append(")|(");
- pattern.append(RULE_PATTERN.matcher(rules[i].mPrefix).replaceAll("\\\\$0"));
- }
- mPattern = Pattern.compile(pattern.append(")").toString());
- mRules = rules;
- }
-
- /**
- * Match a string against every Rule and find one that matches.
- * @param uri to match against the Rules in the rewriter.
- * @return the most specific matching Rule, or Rule.DEFAULT if none match.
- */
- public Rule matchRule(String url) {
- Matcher matcher = mPattern.matcher(url);
- if (matcher.lookingAt()) {
- for (int i = 0; i < mRules.length; ++i) {
- if (matcher.group(i + 1) != null) {
- return mRules[i]; // Rules are sorted most specific first.
- }
- }
- }
- return Rule.DEFAULT;
- }
-
- /**
- * Get the (possibly cached) UrlRules based on the rules in Gservices.
- * @param resolver to use for accessing the Gservices database.
- * @return an updated UrlRules instance
- */
- public static synchronized UrlRules getRules(ContentResolver resolver) {
- String digest = Settings.Gservices.getString(resolver,
- Settings.Gservices.PROVISIONING_DIGEST);
- if (sCachedDigest != null && sCachedDigest.equals(digest)) {
- // The digest is the same, so the rules are the same.
- if (LOCAL_LOGV) Log.v(TAG, "Using cached rules for digest: " + digest);
- return sCachedRules;
- }
-
- if (LOCAL_LOGV) Log.v(TAG, "Scanning for Gservices \"url:*\" rules");
- Cursor cursor = resolver.query(Settings.Gservices.CONTENT_URI,
- new String[] {
- Settings.Gservices.NAME,
- Settings.Gservices.VALUE
- },
- Settings.Gservices.NAME + " like \"url:%\"", null,
- Settings.Gservices.NAME);
- try {
- ArrayList<Rule> rules = new ArrayList<Rule>();
- while (cursor.moveToNext()) {
- try {
- String name = cursor.getString(0).substring(4); // "url:X"
- String value = cursor.getString(1);
- if (value == null || value.length() == 0) continue;
- if (LOCAL_LOGV) Log.v(TAG, " Rule " + name + ": " + value);
- rules.add(new Rule(name, value));
- } catch (RuleFormatException e) {
- // Oops, Gservices has an invalid rule! Skip it.
- Log.e(TAG, "Invalid rule from Gservices", e);
- Checkin.logEvent(resolver,
- Checkin.Events.Tag.GSERVICES_ERROR, e.toString());
- }
- }
- sCachedRules = new UrlRules(rules.toArray(new Rule[rules.size()]));
- sCachedDigest = digest;
- if (LOCAL_LOGV) Log.v(TAG, "New rules stored for digest: " + digest);
- } finally {
- cursor.close();
- }
-
- return sCachedRules;
- }
-}
diff --git a/core/java/com/google/android/util/SimplePullParser.java b/core/java/com/google/android/util/SimplePullParser.java
deleted file mode 100644
index 031790b..0000000
--- a/core/java/com/google/android/util/SimplePullParser.java
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.util;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringReader;
-import java.io.Reader;
-import java.io.Closeable;
-
-import android.util.Xml;
-import android.util.Log;
-
-/**
- * This is an abstraction of a pull parser that provides several benefits:<ul>
- * <li>it is easier to use robustly because it makes it trivial to handle unexpected tags (which
- * might have children)</li>
- * <li>it makes the handling of text (cdata) blocks more convenient</li>
- * <li>it provides convenient methods for getting a mandatory attribute (and throwing an exception
- * if it is missing) or an optional attribute (and using a default value if it is missing)
- * </ul>
- */
-public class SimplePullParser {
- public static final String TEXT_TAG = "![CDATA[";
-
- private String mLogTag = null;
- private final XmlPullParser mParser;
- private Closeable source;
- private String mCurrentStartTag;
-
- /**
- * Constructs a new SimplePullParser to parse the stream
- * @param stream stream to parse
- * @param encoding the encoding to use
- */
- public SimplePullParser(InputStream stream, String encoding)
- throws ParseException, IOException {
- try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, encoding);
- moveToStartDocument(parser);
- mParser = parser;
- mCurrentStartTag = null;
- source = stream;
- } catch (XmlPullParserException e) {
- throw new ParseException(e);
- }
- }
-
- /**
- * Constructs a new SimplePullParser to parse the xml
- * @param parser the underlying parser to use
- */
- public SimplePullParser(XmlPullParser parser) {
- mParser = parser;
- mCurrentStartTag = null;
- source = null;
- }
-
- /**
- * Constructs a new SimplePullParser to parse the xml
- * @param xml the xml to parse
- */
- public SimplePullParser(String xml) throws IOException, ParseException {
- this(new StringReader(xml));
- }
-
- /**
- * Constructs a new SimplePullParser to parse the xml
- * @param reader a reader containing the xml
- */
- public SimplePullParser(Reader reader) throws IOException, ParseException {
- try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(reader);
- moveToStartDocument(parser);
- mParser = parser;
- mCurrentStartTag = null;
- source = reader;
- } catch (XmlPullParserException e) {
- throw new ParseException(e);
- }
- }
-
- private static void moveToStartDocument(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- int eventType;
- eventType = parser.getEventType();
- if (eventType != XmlPullParser.START_DOCUMENT) {
- throw new XmlPullParserException("Not at start of response");
- }
- }
-
- /**
- * Enables logging to the provided log tag. A basic representation of the xml will be logged as
- * the xml is parsed. No logging is done unless this is called.
- *
- * @param logTag the log tag to use when logging
- */
- public void setLogTag(String logTag) {
- mLogTag = logTag;
- }
-
- /**
- * Returns the tag of the next element whose depth is parentDepth plus one
- * or null if there are no more such elements before the next start tag. When this returns,
- * getDepth() and all methods relating to attributes will refer to the element whose tag is
- * returned.
- *
- * @param parentDepth the depth of the parrent of the item to be returned
- * @param textBuilder if null then text blocks will be ignored. If
- * non-null then text blocks will be added to the builder and TEXT_TAG
- * will be returned when one is found
- * @return the next of the next child element's tag, TEXT_TAG if a text block is found, or null
- * if there are no more child elements or DATA blocks
- * @throws IOException propogated from the underlying parser
- * @throws ParseException if there was an error parsing the xml.
- */
- public String nextTagOrText(int parentDepth, StringBuilder textBuilder)
- throws IOException, ParseException {
- while (true) {
- int eventType = 0;
- try {
- eventType = mParser.next();
- } catch (XmlPullParserException e) {
- throw new ParseException(e);
- }
- int depth = mParser.getDepth();
- mCurrentStartTag = null;
-
- if (eventType == XmlPullParser.START_TAG && depth == parentDepth + 1) {
- mCurrentStartTag = mParser.getName();
- if (mLogTag != null && Log.isLoggable(mLogTag, Log.DEBUG)) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < depth; i++) sb.append(" ");
- sb.append("<").append(mParser.getName());
- int count = mParser.getAttributeCount();
- for (int i = 0; i < count; i++) {
- sb.append(" ");
- sb.append(mParser.getAttributeName(i));
- sb.append("=\"");
- sb.append(mParser.getAttributeValue(i));
- sb.append("\"");
- }
- sb.append(">");
- Log.d(mLogTag, sb.toString());
- }
- return mParser.getName();
- }
-
- if (eventType == XmlPullParser.END_TAG && depth == parentDepth) {
- if (mLogTag != null && Log.isLoggable(mLogTag, Log.DEBUG)) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < depth; i++) sb.append(" ");
- sb.append("</>"); // Not quite valid xml but it gets the job done.
- Log.d(mLogTag, sb.toString());
- }
- return null;
- }
-
- if (eventType == XmlPullParser.END_DOCUMENT && parentDepth == 0) {
- // we could just rely on the caller calling close(), which it should, but try
- // to auto-close for clients that might have missed doing so.
- if (source != null) {
- source.close();
- source = null;
- }
- return null;
- }
-
- if (eventType == XmlPullParser.TEXT && depth == parentDepth) {
- if (textBuilder == null) {
- continue;
- }
- String text = mParser.getText();
- textBuilder.append(text);
- return TEXT_TAG;
- }
- }
- }
-
- /**
- * The same as nextTagOrTexxt(int, StringBuilder) but ignores text blocks.
- */
- public String nextTag(int parentDepth) throws IOException, ParseException {
- return nextTagOrText(parentDepth, null /* ignore text */);
- }
-
- /**
- * Returns the depth of the current element. The depth is 0 before the first
- * element has been returned, 1 after that, etc.
- *
- * @return the depth of the current element
- */
- public int getDepth() {
- return mParser.getDepth();
- }
-
- /**
- * Consumes the rest of the children, accumulating any text at this level into the builder.
- *
- * @param textBuilder the builder to contain any text
- * @throws IOException propogated from the XmlPullParser
- * @throws ParseException if there was an error parsing the xml.
- */
- public void readRemainingText(int parentDepth, StringBuilder textBuilder)
- throws IOException, ParseException {
- while (nextTagOrText(parentDepth, textBuilder) != null) {
- }
- }
-
- /**
- * Returns the number of attributes on the current element.
- *
- * @return the number of attributes on the current element
- */
- public int numAttributes() {
- return mParser.getAttributeCount();
- }
-
- /**
- * Returns the name of the nth attribute on the current element.
- *
- * @return the name of the nth attribute on the current element
- */
- public String getAttributeName(int i) {
- return mParser.getAttributeName(i);
- }
-
- /**
- * Returns the namespace of the nth attribute on the current element.
- *
- * @return the namespace of the nth attribute on the current element
- */
- public String getAttributeNamespace(int i) {
- return mParser.getAttributeNamespace(i);
- }
-
- /**
- * Returns the string value of the named attribute.
- *
- * @param namespace the namespace of the attribute
- * @param name the name of the attribute
- * @param defaultValue the value to return if the attribute is not specified
- * @return the value of the attribute
- */
- public String getStringAttribute(
- String namespace, String name, String defaultValue) {
- String value = mParser.getAttributeValue(namespace, name);
- if (null == value) return defaultValue;
- return value;
- }
-
- /**
- * Returns the string value of the named attribute. An exception will
- * be thrown if the attribute is not present.
- *
- * @param namespace the namespace of the attribute
- * @param name the name of the attribute @return the value of the attribute
- * @throws ParseException thrown if the attribute is missing
- */
- public String getStringAttribute(String namespace, String name) throws ParseException {
- String value = mParser.getAttributeValue(namespace, name);
- if (null == value) {
- throw new ParseException(
- "missing '" + name + "' attribute on '" + mCurrentStartTag + "' element");
- }
- return value;
- }
-
- /**
- * Returns the string value of the named attribute. An exception will
- * be thrown if the attribute is not a valid integer.
- *
- * @param namespace the namespace of the attribute
- * @param name the name of the attribute
- * @param defaultValue the value to return if the attribute is not specified
- * @return the value of the attribute
- * @throws ParseException thrown if the attribute not a valid integer.
- */
- public int getIntAttribute(String namespace, String name, int defaultValue)
- throws ParseException {
- String value = mParser.getAttributeValue(namespace, name);
- if (null == value) return defaultValue;
- try {
- return Integer.parseInt(value);
- } catch (NumberFormatException e) {
- throw new ParseException("Cannot parse '" + value + "' as an integer");
- }
- }
-
- /**
- * Returns the string value of the named attribute. An exception will
- * be thrown if the attribute is not present or is not a valid integer.
- *
- * @param namespace the namespace of the attribute
- * @param name the name of the attribute @return the value of the attribute
- * @throws ParseException thrown if the attribute is missing or not a valid integer.
- */
- public int getIntAttribute(String namespace, String name)
- throws ParseException {
- String value = getStringAttribute(namespace, name);
- try {
- return Integer.parseInt(value);
- } catch (NumberFormatException e) {
- throw new ParseException("Cannot parse '" + value + "' as an integer");
- }
- }
-
- /**
- * Returns the string value of the named attribute. An exception will
- * be thrown if the attribute is not a valid long.
- *
- * @param namespace the namespace of the attribute
- * @param name the name of the attribute @return the value of the attribute
- * @throws ParseException thrown if the attribute is not a valid long.
- */
- public long getLongAttribute(String namespace, String name, long defaultValue)
- throws ParseException {
- String value = mParser.getAttributeValue(namespace, name);
- if (null == value) return defaultValue;
- try {
- return Long.parseLong(value);
- } catch (NumberFormatException e) {
- throw new ParseException("Cannot parse '" + value + "' as a long");
- }
- }
-
- /**
- * Close this SimplePullParser and any underlying resources (e.g., its InputStream or
- * Reader source) used by this SimplePullParser.
- */
- public void close() {
- if (source != null) {
- try {
- source.close();
- } catch (IOException ioe) {
- // ignore
- }
- }
- }
-
- /**
- * Returns the string value of the named attribute. An exception will
- * be thrown if the attribute is not present or is not a valid long.
- *
- * @param namespace the namespace of the attribute
- * @param name the name of the attribute @return the value of the attribute
- * @throws ParseException thrown if the attribute is missing or not a valid long.
- */
- public long getLongAttribute(String namespace, String name)
- throws ParseException {
- String value = getStringAttribute(namespace, name);
- try {
- return Long.parseLong(value);
- } catch (NumberFormatException e) {
- throw new ParseException("Cannot parse '" + value + "' as a long");
- }
- }
-
- public static final class ParseException extends Exception {
- public ParseException(String message) {
- super(message);
- }
-
- public ParseException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public ParseException(Throwable cause) {
- super(cause);
- }
- }
-}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index c92a86c..67a0bda 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -165,6 +165,7 @@ LOCAL_SHARED_LIBRARIES := \
libEGL \
libGLESv1_CM \
libGLESv2 \
+ libETC1 \
libhardware \
libhardware_legacy \
libsonivox \
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 238ece1..7c7bfeb 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -46,7 +46,7 @@ static SkTypeface* Typeface_createFromTypeface(JNIEnv* env, jobject, SkTypeface*
}
static void Typeface_unref(JNIEnv* env, jobject obj, SkTypeface* face) {
- face->unref();
+ SkSafeUnref(face);
}
static int Typeface_getStyle(JNIEnv* env, jobject obj, SkTypeface* face) {
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 4041346..589b255 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -23,6 +23,7 @@
#include <dlfcn.h>
#include <GLES/gl.h>
+#include <ETC1/etc1.h>
#include <core/SkBitmap.h>
@@ -39,6 +40,7 @@ namespace android {
static jclass gIAEClass;
static jclass gUOEClass;
+static jclass gAIOOBEClass;
static inline
void mx4transform(float x, float y, float z, float w, const float* pM, float* pDest) {
@@ -712,6 +714,297 @@ static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
}
/*
+ * ETC1 methods.
+ */
+
+static jclass nioAccessClass;
+static jclass bufferClass;
+static jmethodID getBasePointerID;
+static jmethodID getBaseArrayID;
+static jmethodID getBaseArrayOffsetID;
+static jfieldID positionID;
+static jfieldID limitID;
+static jfieldID elementSizeShiftID;
+
+/* Cache method IDs each time the class is loaded. */
+
+static void
+nativeClassInitBuffer(JNIEnv *_env)
+{
+ jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
+ nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
+
+ jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
+ bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
+
+ getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+ "getBasePointer", "(Ljava/nio/Buffer;)J");
+ getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+ getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+ positionID = _env->GetFieldID(bufferClass, "position", "I");
+ limitID = _env->GetFieldID(bufferClass, "limit", "I");
+ elementSizeShiftID =
+ _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+}
+
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jint *remaining)
+{
+ jint position;
+ jint limit;
+ jint elementSizeShift;
+ jlong pointer;
+ jint offset;
+ void *data;
+
+ position = _env->GetIntField(buffer, positionID);
+ limit = _env->GetIntField(buffer, limitID);
+ elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+ *remaining = (limit - position) << elementSizeShift;
+ pointer = _env->CallStaticLongMethod(nioAccessClass,
+ getBasePointerID, buffer);
+ if (pointer != 0L) {
+ return (void *) (jint) pointer;
+ }
+ return NULL;
+}
+
+class BufferHelper {
+public:
+ BufferHelper(JNIEnv *env, jobject buffer) {
+ mEnv = env;
+ mBuffer = buffer;
+ mData = NULL;
+ mRemaining = 0;
+ }
+
+ bool checkPointer(const char* errorMessage) {
+ if (mBuffer) {
+ mData = getPointer(mEnv, mBuffer, &mRemaining);
+ if (mData == NULL) {
+ mEnv->ThrowNew(gIAEClass, errorMessage);
+ }
+ return mData != NULL;
+ } else {
+ mEnv->ThrowNew(gIAEClass, errorMessage);
+ return false;
+ }
+ }
+
+ inline void* getData() {
+ return mData;
+ }
+
+ inline jint remaining() {
+ return mRemaining;
+ }
+
+private:
+ JNIEnv* mEnv;
+ jobject mBuffer;
+ void* mData;
+ jint mRemaining;
+};
+
+/**
+ * Encode a block of pixels.
+ *
+ * @param in a pointer to a ETC1_DECODED_BLOCK_SIZE array of bytes that represent a
+ * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
+ * value of pixel (x, y).
+ *
+ * @param validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether
+ * the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing.
+ *
+ * @param out an ETC1 compressed version of the data.
+ *
+ */
+static void etc1_encodeBlock(JNIEnv *env, jclass clazz,
+ jobject in, jint validPixelMask, jobject out) {
+ if (validPixelMask < 0 || validPixelMask > 15) {
+ env->ThrowNew(gIAEClass, "validPixelMask");
+ return;
+ }
+ BufferHelper inB(env, in);
+ BufferHelper outB(env, out);
+ if (inB.checkPointer("in") && outB.checkPointer("out")) {
+ if (inB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
+ env->ThrowNew(gIAEClass, "in's remaining data < DECODED_BLOCK_SIZE");
+ } else if (outB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
+ env->ThrowNew(gIAEClass, "out's remaining data < ENCODED_BLOCK_SIZE");
+ } else {
+ etc1_encode_block((etc1_byte*) inB.getData(), validPixelMask,
+ (etc1_byte*) outB.getData());
+ }
+ }
+}
+
+/**
+ * Decode a block of pixels.
+ *
+ * @param in an ETC1 compressed version of the data.
+ *
+ * @param out a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a
+ * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
+ * value of pixel (x, y).
+ */
+static void etc1_decodeBlock(JNIEnv *env, jclass clazz,
+ jobject in, jobject out){
+ BufferHelper inB(env, in);
+ BufferHelper outB(env, out);
+ if (inB.checkPointer("in") && outB.checkPointer("out")) {
+ if (inB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
+ env->ThrowNew(gIAEClass, "in's remaining data < ENCODED_BLOCK_SIZE");
+ } else if (outB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
+ env->ThrowNew(gIAEClass, "out's remaining data < DECODED_BLOCK_SIZE");
+ } else {
+ etc1_decode_block((etc1_byte*) inB.getData(),
+ (etc1_byte*) outB.getData());
+ }
+ }
+}
+
+/**
+ * Return the size of the encoded image data (does not include size of PKM header).
+ */
+static jint etc1_getEncodedDataSize(JNIEnv *env, jclass clazz,
+ jint width, jint height) {
+ return etc1_get_encoded_data_size(width, height);
+}
+
+/**
+ * Encode an entire image.
+ * @param in pointer to the image data. Formatted such that
+ * pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset;
+ * @param out pointer to encoded data. Must be large enough to store entire encoded image.
+ */
+static void etc1_encodeImage(JNIEnv *env, jclass clazz,
+ jobject in, jint width, jint height,
+ jint pixelSize, jint stride, jobject out) {
+ if (pixelSize < 2 || pixelSize > 3) {
+ env->ThrowNew(gIAEClass, "pixelSize must be 2 or 3");
+ return;
+ }
+ BufferHelper inB(env, in);
+ BufferHelper outB(env, out);
+ if (inB.checkPointer("in") && outB.checkPointer("out")) {
+ jint imageSize = stride * height;
+ jint encodedImageSize = etc1_get_encoded_data_size(width, height);
+ if (inB.remaining() < imageSize) {
+ env->ThrowNew(gIAEClass, "in's remaining data < image size");
+ } else if (outB.remaining() < encodedImageSize) {
+ env->ThrowNew(gIAEClass, "out's remaining data < encoded image size");
+ } else {
+ int result = etc1_encode_image((etc1_byte*) inB.getData(),
+ width, height, pixelSize,
+ stride,
+ (etc1_byte*) outB.getData());
+ }
+ }
+}
+
+/**
+ * Decode an entire image.
+ * @param in the encoded data.
+ * @param out pointer to the image data. Will be written such that
+ * pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be
+ * large enough to store entire image.
+ */
+static void etc1_decodeImage(JNIEnv *env, jclass clazz,
+ jobject in, jobject out,
+ jint width, jint height,
+ jint pixelSize, jint stride) {
+ if (pixelSize < 2 || pixelSize > 3) {
+ env->ThrowNew(gIAEClass, "pixelSize must be 2 or 3");
+ return;
+ }
+ BufferHelper inB(env, in);
+ BufferHelper outB(env, out);
+ if (inB.checkPointer("in") && outB.checkPointer("out")) {
+ jint imageSize = stride * height;
+ jint encodedImageSize = etc1_get_encoded_data_size(width, height);
+ if (inB.remaining() < encodedImageSize) {
+ env->ThrowNew(gIAEClass, "in's remaining data < encoded image size");
+ } else if (outB.remaining() < imageSize) {
+ env->ThrowNew(gIAEClass, "out's remaining data < image size");
+ } else {
+ int result = etc1_decode_image((etc1_byte*) inB.getData(),
+ (etc1_byte*) outB.getData(),
+ width, height, pixelSize,
+ stride);
+ }
+ }
+}
+
+/**
+ * Format a PKM header
+ */
+static void etc1_formatHeader(JNIEnv *env, jclass clazz,
+ jobject header, jint width, jint height) {
+ BufferHelper headerB(env, header);
+ if (headerB.checkPointer("header") ){
+ if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
+ env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE");
+ } else {
+ etc1_pkm_format_header((etc1_byte*) headerB.getData(), width, height);
+ }
+ }
+}
+
+/**
+ * Check if a PKM header is correctly formatted.
+ */
+static jboolean etc1_isValid(JNIEnv *env, jclass clazz,
+ jobject header) {
+ jboolean result = false;
+ BufferHelper headerB(env, header);
+ if (headerB.checkPointer("header") ){
+ if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
+ env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE");
+ } else {
+ result = etc1_pkm_is_valid((etc1_byte*) headerB.getData());
+ }
+ }
+ return result;
+}
+
+/**
+ * Read the image width from a PKM header
+ */
+static jint etc1_getWidth(JNIEnv *env, jclass clazz,
+ jobject header) {
+ jint result = 0;
+ BufferHelper headerB(env, header);
+ if (headerB.checkPointer("header") ){
+ if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
+ env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE");
+ } else {
+ result = etc1_pkm_get_width((etc1_byte*) headerB.getData());
+ }
+ }
+ return result;
+}
+
+/**
+ * Read the image height from a PKM header
+ */
+static int etc1_getHeight(JNIEnv *env, jclass clazz,
+ jobject header) {
+ jint result = 0;
+ BufferHelper headerB(env, header);
+ if (headerB.checkPointer("header") ){
+ if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
+ env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE");
+ } else {
+ result = etc1_pkm_get_height((etc1_byte*) headerB.getData());
+ }
+ }
+ return result;
+}
+
+/*
* JNI registration
*/
@@ -721,6 +1014,8 @@ lookupClasses(JNIEnv* env) {
env->FindClass("java/lang/IllegalArgumentException"));
gUOEClass = (jclass) env->NewGlobalRef(
env->FindClass("java/lang/UnsupportedOperationException"));
+ gAIOOBEClass = (jclass) env->NewGlobalRef(
+ env->FindClass("java/lang/ArrayIndexOutOfBoundsException"));
}
static JNINativeMethod gMatrixMethods[] = {
@@ -742,6 +1037,18 @@ static JNINativeMethod gUtilsMethods[] = {
{ "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
};
+static JNINativeMethod gEtc1Methods[] = {
+ { "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock },
+ { "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock },
+ { "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize },
+ { "encodeImage", "(Ljava/nio/Buffer;IIIILjava/nio/Buffer;)V", (void*) etc1_encodeImage },
+ { "decodeImage", "(Ljava/nio/Buffer;Ljava/nio/Buffer;IIII)V", (void*) etc1_decodeImage },
+ { "formatHeader", "(Ljava/nio/Buffer;II)V", (void*) etc1_formatHeader },
+ { "isValid", "(Ljava/nio/Buffer;)Z", (void*) etc1_isValid },
+ { "getWidth", "(Ljava/nio/Buffer;)I", (void*) etc1_getWidth },
+ { "getHeight", "(Ljava/nio/Buffer;)I", (void*) etc1_getHeight },
+};
+
typedef struct _ClassRegistrationInfo {
const char* classPath;
JNINativeMethod* methods;
@@ -752,11 +1059,13 @@ static ClassRegistrationInfo gClasses[] = {
{"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
{"android/opengl/Visibility", gVisiblityMethods, NELEM(gVisiblityMethods)},
{"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
+ {"android/opengl/ETC1", gEtc1Methods, NELEM(gEtc1Methods)},
};
int register_android_opengl_classes(JNIEnv* env)
{
lookupClasses(env);
+ nativeClassInitBuffer(env);
int result = 0;
for (int i = 0; i < NELEM(gClasses); i++) {
ClassRegistrationInfo* cri = &gClasses[i];
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index d57e526..11463a2 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -220,7 +220,7 @@ void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr)
break;
default:
// TODO: Change to LOGV
- LOGD("dataCallback(%d, %p)", msgType, dataPtr.get());
+ LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
copyAndPost(env, dataPtr, msgType);
break;
}
diff --git a/core/jni/android_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp
index 1ae3ec7..ee8d836 100644
--- a/core/jni/android_os_MemoryFile.cpp
+++ b/core/jni/android_os_MemoryFile.cpp
@@ -30,8 +30,6 @@ static jobject android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring na
{
const char* namestr = (name ? env->GetStringUTFChars(name, NULL) : NULL);
- // round up length to page boundary
- length = (((length - 1) / getpagesize()) + 1) * getpagesize();
int result = ashmem_create_region(namestr, length);
if (name)
@@ -118,7 +116,7 @@ static void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDe
}
}
-static jint android_os_MemoryFile_get_mapped_size(JNIEnv* env, jobject clazz,
+static jint android_os_MemoryFile_get_size(JNIEnv* env, jobject clazz,
jobject fileDescriptor) {
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
// Use ASHMEM_GET_SIZE to find out if the fd refers to an ashmem region.
@@ -146,8 +144,8 @@ static const JNINativeMethod methods[] = {
{"native_read", "(Ljava/io/FileDescriptor;I[BIIIZ)I", (void*)android_os_MemoryFile_read},
{"native_write", "(Ljava/io/FileDescriptor;I[BIIIZ)V", (void*)android_os_MemoryFile_write},
{"native_pin", "(Ljava/io/FileDescriptor;Z)V", (void*)android_os_MemoryFile_pin},
- {"native_get_mapped_size", "(Ljava/io/FileDescriptor;)I",
- (void*)android_os_MemoryFile_get_mapped_size}
+ {"native_get_size", "(Ljava/io/FileDescriptor;)I",
+ (void*)android_os_MemoryFile_get_size}
};
static const char* const kClassPathName = "android/os/MemoryFile";
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index 7a3bbbb..4eab4b3 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -38,6 +38,7 @@ namespace android {
#ifdef HAVE_BLUETOOTH
static jmethodID method_onSinkPropertyChanged;
+static jmethodID method_onConnectSinkResult;
typedef struct {
JavaVM *vm;
@@ -47,6 +48,7 @@ typedef struct {
} native_data_t;
static native_data_t *nat = NULL; // global native data
+static void onConnectSinkResult(DBusMessage *msg, void *user, void *n);
static Properties sink_properties[] = {
{"State", DBUS_TYPE_STRING},
@@ -133,9 +135,12 @@ static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) {
LOGV(__FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
+ int len = env->GetStringLength(path) + 1;
+ char *context_path = (char *)calloc(len, sizeof(char));
+ strlcpy(context_path, c_path, len); // for callback
- bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
- c_path, "org.bluez.AudioSink", "Connect",
+ bool ret = dbus_func_args_async(env, nat->conn, -1, onConnectSinkResult, context_path,
+ nat, c_path, "org.bluez.AudioSink", "Connect",
DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(path, c_path);
@@ -237,6 +242,31 @@ DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
return result;
}
+
+void onConnectSinkResult(DBusMessage *msg, void *user, void *n) {
+ LOGV(__FUNCTION__);
+
+ native_data_t *nat = (native_data_t *)n;
+ const char *path = (const char *)user;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env;
+ nat->vm->GetEnv((void**)&env, nat->envVer);
+
+
+ bool result = JNI_TRUE;
+ if (dbus_set_error_from_message(&err, msg)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ result = JNI_FALSE;
+ }
+ LOGV("... Device Path = %s, result = %d", path, result);
+ env->CallVoidMethod(nat->me,
+ method_onConnectSinkResult,
+ env->NewStringUTF(path),
+ result);
+ free(user);
+}
+
#endif
@@ -244,7 +274,7 @@ static JNINativeMethod sMethods[] = {
{"initNative", "()Z", (void *)initNative},
{"cleanupNative", "()V", (void *)cleanupNative},
- /* Bluez audio 4.40 API */
+ /* Bluez audio 4.47 API */
{"connectSinkNative", "(Ljava/lang/String;)Z", (void *)connectSinkNative},
{"disconnectSinkNative", "(Ljava/lang/String;)Z", (void *)disconnectSinkNative},
{"suspendSinkNative", "(Ljava/lang/String;)Z", (void*)suspendSinkNative},
@@ -263,6 +293,8 @@ int register_android_server_BluetoothA2dpService(JNIEnv *env) {
#ifdef HAVE_BLUETOOTH
method_onSinkPropertyChanged = env->GetMethodID(clazz, "onSinkPropertyChanged",
"(Ljava/lang/String;[Ljava/lang/String;)V");
+ method_onConnectSinkResult = env->GetMethodID(clazz, "onConnectSinkResult",
+ "(Ljava/lang/String;Z)V");
#endif
return AndroidRuntime::registerNativeMethods(env,
diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp
index fde6ca6..d89a7e6 100644
--- a/core/jni/android_text_format_Time.cpp
+++ b/core/jni/android_text_format_Time.cpp
@@ -382,7 +382,7 @@ static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected)
jchar c = s[spos];
if (c != expected) {
char msg[100];
- sprintf(msg, "Unexpected %c at pos=%d. Expected %c.", c, spos,
+ sprintf(msg, "Unexpected character 0x%02x at pos=%d. Expected %c.", c, spos,
expected);
jniThrowException(env, "android/util/TimeFormatException", msg);
return false;
@@ -483,6 +483,12 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
int n;
jboolean inUtc = false;
+ if (len < 10) {
+ jniThrowException(env, "android/util/TimeFormatException",
+ "Time input is too short; must be at least 10 characters");
+ return false;
+ }
+
// year
n = get_char(env, s, 0, 1000, &thrown);
n += get_char(env, s, 1, 100, &thrown);
@@ -510,7 +516,7 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
if (thrown) return false;
env->SetIntField(This, g_mdayField, n);
- if (len >= 17) {
+ if (len >= 19) {
// T
if (!check_char(env, s, 10, 'T')) return false;
@@ -541,10 +547,19 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
if (thrown) return false;
env->SetIntField(This, g_secField, n);
- // skip the '.XYZ' -- we don't care about subsecond precision.
+ // skip the '.XYZ' -- we don't care about subsecond precision.
+ int tz_index = 19;
+ if (tz_index < len && s[tz_index] == '.') {
+ do {
+ tz_index++;
+ } while (tz_index < len
+ && s[tz_index] >= '0'
+ && s[tz_index] <= '9');
+ }
+
int offset = 0;
- if (len >= 23) {
- char c = s[23];
+ if (len > tz_index) {
+ char c = s[tz_index];
// NOTE: the offset is meant to be subtracted to get from local time
// to UTC. we therefore use 1 for '-' and -1 for '+'.
@@ -561,27 +576,34 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
break;
default:
char msg[100];
- sprintf(msg, "Unexpected %c at position 19. Expected + or -",
- c);
+ sprintf(msg, "Unexpected character 0x%02x at position %d. Expected + or -",
+ c, tz_index);
jniThrowException(env, "android/util/TimeFormatException", msg);
return false;
}
inUtc = true;
if (offset != 0) {
+ if (len < tz_index + 5) {
+ char msg[100];
+ sprintf(msg, "Unexpected length; should be %d characters", tz_index + 5);
+ jniThrowException(env, "android/util/TimeFormatException", msg);
+ return false;
+ }
+
// hour
- n = get_char(env, s, 24, 10, &thrown);
- n += get_char(env, s, 25, 1, &thrown);
+ n = get_char(env, s, tz_index + 1, 10, &thrown);
+ n += get_char(env, s, tz_index + 2, 1, &thrown);
if (thrown) return false;
n *= offset;
hour += n;
// :
- if (!check_char(env, s, 26, ':')) return false;
+ if (!check_char(env, s, tz_index + 3, ':')) return false;
// minute
- n = get_char(env, s, 27, 10, &thrown);
- n += get_char(env, s, 28, 1, &thrown);
+ n = get_char(env, s, tz_index + 4, 10, &thrown);
+ n += get_char(env, s, tz_index + 5, 1, &thrown);
if (thrown) return false;
n *= offset;
minute += n;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index e83d2e2..2fff727 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -524,7 +524,6 @@ static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject
}
for (int i=0; i<N; i++) {
- LOGD("locale %2d: '%s'", i, locales[i].string());
env->SetObjectArrayElement(result, i, env->NewStringUTF(locales[i].string()));
}
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 34b7c89..78356cf 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -21,13 +21,6 @@
#include "jni.h"
#include "cutils/logger.h"
-#define END_DELIMITER '\n'
-#define INT_BUFFER_SIZE (sizeof(jbyte)+sizeof(jint)+sizeof(END_DELIMITER))
-#define LONG_BUFFER_SIZE (sizeof(jbyte)+sizeof(jlong)+sizeof(END_DELIMITER))
-#define INITAL_BUFFER_CAPACITY 256
-
-#define MAX(a,b) ((a>b)?a:b)
-
namespace android {
static jclass gCollectionClass;
@@ -47,107 +40,6 @@ static jfieldID gLongValueID;
static jclass gStringClass;
-struct ByteBuf {
- size_t len;
- size_t capacity;
- uint8_t* buf;
-
- ByteBuf(size_t initSize) {
- buf = (uint8_t*)malloc(initSize);
- len = 0;
- capacity = initSize;
- }
-
- ~ByteBuf() {
- free(buf);
- }
-
- bool ensureExtraCapacity(size_t extra) {
- size_t spaceNeeded = len + extra;
- if (spaceNeeded > capacity) {
- size_t newCapacity = MAX(spaceNeeded, 2 * capacity);
- void* newBuf = realloc(buf, newCapacity);
- if (newBuf == NULL) {
- return false;
- }
- capacity = newCapacity;
- buf = (uint8_t*)newBuf;
- return true;
- } else {
- return true;
- }
- }
-
- void putIntEvent(jint value) {
- bool succeeded = ensureExtraCapacity(INT_BUFFER_SIZE);
- buf[len++] = EVENT_TYPE_INT;
- memcpy(buf+len, &value, sizeof(jint));
- len += sizeof(jint);
- }
-
- void putByte(uint8_t value) {
- bool succeeded = ensureExtraCapacity(sizeof(uint8_t));
- buf[len++] = value;
- }
-
- void putLongEvent(jlong value) {
- bool succeeded = ensureExtraCapacity(LONG_BUFFER_SIZE);
- buf[len++] = EVENT_TYPE_LONG;
- memcpy(buf+len, &value, sizeof(jlong));
- len += sizeof(jlong);
- }
-
-
- void putStringEvent(JNIEnv* env, jstring value) {
- const char* strValue = env->GetStringUTFChars(value, NULL);
- uint32_t strLen = strlen(strValue); //env->GetStringUTFLength(value);
- bool succeeded = ensureExtraCapacity(1 + sizeof(uint32_t) + strLen);
- buf[len++] = EVENT_TYPE_STRING;
- memcpy(buf+len, &strLen, sizeof(uint32_t));
- len += sizeof(uint32_t);
- memcpy(buf+len, strValue, strLen);
- env->ReleaseStringUTFChars(value, strValue);
- len += strLen;
- }
-
- void putList(JNIEnv* env, jobject list) {
- jobjectArray items = (jobjectArray) env->GetObjectField(list, gListItemsID);
- if (items == NULL) {
- jniThrowException(env, "java/lang/NullPointerException", NULL);
- return;
- }
-
- jsize numItems = env->GetArrayLength(items);
- putByte(EVENT_TYPE_LIST);
- putByte(numItems);
- // We'd like to call GetPrimitveArrayCritical() but that might
- // not be safe since we're going to be doing some I/O
- for (int i = 0; i < numItems; i++) {
- jobject item = env->GetObjectArrayElement(items, i);
- if (env->IsInstanceOf(item, gIntegerClass)) {
- jint intVal = env->GetIntField(item, gIntegerValueID);
- putIntEvent(intVal);
- } else if (env->IsInstanceOf(item, gLongClass)) {
- jlong longVal = env->GetLongField(item, gLongValueID);
- putLongEvent(longVal);
- } else if (env->IsInstanceOf(item, gStringClass)) {
- putStringEvent(env, (jstring)item);
- } else if (env->IsInstanceOf(item, gListClass)) {
- putList(env, item);
- } else {
- jniThrowException(
- env,
- "java/lang/IllegalArgumentException",
- "Attempt to log an illegal item type.");
- return;
- }
- env->DeleteLocalRef(item);
- }
-
- env->DeleteLocalRef(items);
- }
-};
-
/*
* In class android.util.EventLog:
* static native int writeEvent(int tag, int value)
@@ -170,41 +62,80 @@ static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz,
/*
* In class android.util.EventLog:
- * static native int writeEvent(long tag, List value)
+ * static native int writeEvent(int tag, String value)
*/
-static jint android_util_EventLog_writeEvent_List(JNIEnv* env, jobject clazz,
- jint tag, jobject value) {
- if (value == NULL) {
- jclass clazz = env->FindClass("java/lang/IllegalArgumentException");
- env->ThrowNew(clazz, "writeEvent needs a value.");
- return -1;
- }
- ByteBuf byteBuf(INITAL_BUFFER_CAPACITY);
- byteBuf.putList(env, value);
- byteBuf.putByte((uint8_t)END_DELIMITER);
- int numBytesPut = byteBuf.len;
- int bytesWritten = android_bWriteLog(tag, byteBuf.buf, numBytesPut);
- return bytesWritten;
+static jint android_util_EventLog_writeEvent_String(JNIEnv* env, jobject clazz,
+ jint tag, jstring value) {
+ uint8_t buf[LOGGER_ENTRY_MAX_PAYLOAD];
+
+ // Don't throw NPE -- I feel like it's sort of mean for a logging function
+ // to be all crashy if you pass in NULL -- but make the NULL value explicit.
+ const char *str = value != NULL ? env->GetStringUTFChars(value, NULL) : "NULL";
+ jint len = strlen(str);
+ const int max = sizeof(buf) - sizeof(len) - 2; // Type byte, final newline
+ if (len > max) len = max;
+
+ buf[0] = EVENT_TYPE_STRING;
+ memcpy(&buf[1], &len, sizeof(len));
+ memcpy(&buf[1 + sizeof(len)], str, len);
+ buf[1 + sizeof(len) + len] = '\n';
+
+ if (value != NULL) env->ReleaseStringUTFChars(value, str);
+ return android_bWriteLog(tag, buf, 2 + sizeof(len) + len);
}
/*
* In class android.util.EventLog:
- * static native int writeEvent(int tag, String value)
+ * static native int writeEvent(long tag, Object... value)
*/
-static jint android_util_EventLog_writeEvent_String(JNIEnv* env, jobject clazz,
- jint tag, jstring value) {
+static jint android_util_EventLog_writeEvent_Array(JNIEnv* env, jobject clazz,
+ jint tag, jobjectArray value) {
if (value == NULL) {
- jclass clazz = env->FindClass("java/lang/IllegalArgumentException");
- env->ThrowNew(clazz, "logEvent needs a value.");
- return -1;
+ return android_util_EventLog_writeEvent_String(env, clazz, tag, NULL);
+ }
+
+ uint8_t buf[LOGGER_ENTRY_MAX_PAYLOAD];
+ const size_t max = sizeof(buf) - 1; // leave room for final newline
+ size_t pos = 2; // Save room for type tag & array count
+
+ jsize copied = 0, num = env->GetArrayLength(value);
+ for (; copied < num && copied < 256; ++copied) {
+ jobject item = env->GetObjectArrayElement(value, copied);
+ if (item == NULL || env->IsInstanceOf(item, gStringClass)) {
+ if (pos + 1 + sizeof(jint) > max) break;
+ const char *str = item != NULL ? env->GetStringUTFChars((jstring) item, NULL) : "NULL";
+ jint len = strlen(str);
+ if (pos + 1 + sizeof(len) + len > max) len = max - pos - 1 - sizeof(len);
+ buf[pos++] = EVENT_TYPE_STRING;
+ memcpy(&buf[pos], &len, sizeof(len));
+ memcpy(&buf[pos + sizeof(len)], str, len);
+ pos += sizeof(len) + len;
+ if (item != NULL) env->ReleaseStringUTFChars((jstring) item, str);
+ } else if (env->IsInstanceOf(item, gIntegerClass)) {
+ jint intVal = env->GetIntField(item, gIntegerValueID);
+ if (pos + 1 + sizeof(intVal) > max) break;
+ buf[pos++] = EVENT_TYPE_INT;
+ memcpy(&buf[pos], &intVal, sizeof(intVal));
+ pos += sizeof(intVal);
+ } else if (env->IsInstanceOf(item, gLongClass)) {
+ jlong longVal = env->GetLongField(item, gLongValueID);
+ if (pos + 1 + sizeof(longVal) > max) break;
+ buf[pos++] = EVENT_TYPE_LONG;
+ memcpy(&buf[pos], &longVal, sizeof(longVal));
+ pos += sizeof(longVal);
+ } else {
+ jniThrowException(env,
+ "java/lang/IllegalArgumentException",
+ "Invalid payload item type");
+ return -1;
+ }
+ env->DeleteLocalRef(item);
}
- ByteBuf byteBuf(INITAL_BUFFER_CAPACITY);
- byteBuf.putStringEvent(env, value);
- byteBuf.putByte((uint8_t)END_DELIMITER);
- int numBytesPut = byteBuf.len;
- int bytesWritten = android_bWriteLog(tag, byteBuf.buf, numBytesPut);
- return bytesWritten;
+ buf[0] = EVENT_TYPE_LIST;
+ buf[1] = copied;
+ buf[pos++] = '\n';
+ return android_bWriteLog(tag, buf, pos);
}
/*
@@ -276,81 +207,6 @@ static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
}
/*
- * In class android.util.EventLog:
- * static native void readEvents(String path, Collection<Event> output)
- *
- * Reads events from a file (See Checkin.Aggregation). Events are stored in
- * native raw format (logger_entry + payload).
- */
-static void android_util_EventLog_readEventsFile(JNIEnv* env, jobject clazz, jstring path,
- jobject out) {
- if (path == NULL || out == NULL) {
- jniThrowException(env, "java/lang/NullPointerException", NULL);
- return;
- }
-
- const char *pathString = env->GetStringUTFChars(path, 0);
- int fd = open(pathString, O_RDONLY | O_NONBLOCK);
- env->ReleaseStringUTFChars(path, pathString);
-
- if (fd < 0) {
- jniThrowIOException(env, errno);
- return;
- }
-
- uint8_t buf[LOGGER_ENTRY_MAX_LEN];
- for (;;) {
- // read log entry structure from file
- int len = read(fd, buf, sizeof(logger_entry));
- if (len == 0) {
- break; // end of file
- } else if (len < 0) {
- jniThrowIOException(env, errno);
- } else if ((size_t) len < sizeof(logger_entry)) {
- jniThrowException(env, "java/io/IOException", "Event header too short");
- break;
- }
-
- // read event payload
- logger_entry* entry = (logger_entry*) buf;
- if (entry->len > LOGGER_ENTRY_MAX_PAYLOAD) {
- jniThrowException(env,
- "java/lang/IllegalArgumentException",
- "Too much data for event payload. Corrupt file?");
- break;
- }
-
- len = read(fd, buf + sizeof(logger_entry), entry->len);
- if (len == 0) {
- break; // end of file
- } else if (len < 0) {
- jniThrowIOException(env, errno);
- } else if ((size_t) len < entry->len) {
- jniThrowException(env, "java/io/IOException", "Event payload too short");
- break;
- }
-
- // create EventLog$Event and add it to the collection
- int buffer_size = sizeof(logger_entry) + entry->len;
- jbyteArray array = env->NewByteArray(buffer_size);
- if (array == NULL) break;
-
- jbyte *bytes = env->GetByteArrayElements(array, NULL);
- memcpy(bytes, buf, buffer_size);
- env->ReleaseByteArrayElements(array, bytes, 0);
-
- jobject event = env->NewObject(gEventClass, gEventInitID, array);
- if (event == NULL) break;
-
- env->CallBooleanMethod(out, gCollectionAddID, event);
- env->DeleteLocalRef(event);
- env->DeleteLocalRef(array);
- }
-
- close(fd);
-}
-
-/*
* JNI registration.
*/
static JNINativeMethod gRegisterMethods[] = {
@@ -362,22 +218,17 @@ static JNINativeMethod gRegisterMethods[] = {
(void*) android_util_EventLog_writeEvent_String
},
{ "writeEvent",
- "(ILandroid/util/EventLog$List;)I",
- (void*) android_util_EventLog_writeEvent_List
+ "(I[Ljava/lang/Object;)I",
+ (void*) android_util_EventLog_writeEvent_Array
},
{ "readEvents",
"([ILjava/util/Collection;)V",
(void*) android_util_EventLog_readEvents
},
- { "readEvents",
- "(Ljava/lang/String;Ljava/util/Collection;)V",
- (void*) android_util_EventLog_readEventsFile
- }
};
static struct { const char *name; jclass *clazz; } gClasses[] = {
{ "android/util/EventLog$Event", &gEventClass },
- { "android/util/EventLog$List", &gListClass },
{ "java/lang/Integer", &gIntegerClass },
{ "java/lang/Long", &gLongClass },
{ "java/lang/String", &gStringClass },
@@ -386,7 +237,6 @@ static struct { const char *name; jclass *clazz; } gClasses[] = {
static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
{ &gIntegerClass, "value", "I", &gIntegerValueID },
- { &gListClass, "mItems", "[Ljava/lang/Object;", &gListItemsID },
{ &gLongClass, "value", "J", &gLongValueID },
};
@@ -430,4 +280,3 @@ int register_android_util_EventLog(JNIEnv* env) {
}
}; // namespace android
-
diff --git a/core/res/Android.mk b/core/res/Android.mk
index 78cb86d..7d11148 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -24,7 +24,7 @@ LOCAL_CERTIFICATE := platform
# since these resources will be used by many apps.
LOCAL_AAPT_FLAGS := -x
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
# Install this alongside the libraries.
LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4a7adcc..c49a86a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -403,7 +403,13 @@
android:label="@string/permlab_recordAudio"
android:description="@string/permdesc_recordAudio" />
- <!-- Required to be able to access the camera device. -->
+ <!-- Required to be able to access the camera device.
+ <p>This will automatically enforce the <a
+ href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code
+ &lt;uses-feature&gt;}</a> manifest element for <em>all</em> camera features.
+ If you do not require all camera features or can properly operate if a camera
+ is not available, then you must modify your manifest as appropriate in order to
+ install on devices that don't support all camera features.</p> -->
<permission android:name="android.permission.CAMERA"
android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
android:protectionLevel="dangerous"
@@ -550,12 +556,30 @@
android:label="@string/permlab_changeConfiguration"
android:description="@string/permdesc_changeConfiguration" />
- <!-- Allows an application to restart other applications. -->
+ <!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
+ API is no longer supported. -->
<permission android:name="android.permission.RESTART_PACKAGES"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="dangerous"
- android:label="@string/permlab_restartPackages"
- android:description="@string/permdesc_restartPackages" />
+ android:protectionLevel="normal"
+ android:label="@string/permlab_killBackgroundProcesses"
+ android:description="@string/permdesc_killBackgroundProcesses" />
+
+ <!-- Allows an application to call
+ {@link android.app.ActivityManager#killBackgroundProcesses}. -->
+ <permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="normal"
+ android:label="@string/permlab_killBackgroundProcesses"
+ android:description="@string/permdesc_killBackgroundProcesses" />
+
+ <!-- Allows an application to call
+ {@link android.app.ActivityManager#forceStopPackage}.
+ @hide -->
+ <permission android:name="android.permission.FORCE_STOP_PACKAGES"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature"
+ android:label="@string/permlab_forceStopPackages"
+ android:description="@string/permdesc_forceStopPackages" />
<!-- Allows an application to retrieve state dump information from system
services. -->
@@ -1126,6 +1150,12 @@
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signatureOrSystem" />
+ <!-- Allow an application to read and write the cache partition. -->
+ <permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
+ android:label="@string/permlab_cache_filesystem"
+ android:description="@string/permdesc_cache_filesystem"
+ android:protectionLevel="signatureOrSystem" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/core/res/res/anim/lock_screen_enter.xml b/core/res/res/anim/lock_screen_enter.xml
new file mode 100644
index 0000000..dd47ff8
--- /dev/null
+++ b/core/res/res/anim/lock_screen_enter.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator">
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
+</set>
diff --git a/core/res/res/anim/lock_screen_exit.xml b/core/res/res/anim/lock_screen_exit.xml
index 58bc6db..077fc6b 100644
--- a/core/res/res/anim/lock_screen_exit.xml
+++ b/core/res/res/anim/lock_screen_exit.xml
@@ -17,7 +17,8 @@
*/
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator">
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_interpolator">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:duration="@android:integer/config_longAnimTime" />
</set>
diff --git a/core/res/res/drawable-hdpi/pickerbox_background.png b/core/res/res/drawable-hdpi/pickerbox_background.png
deleted file mode 100644
index 9315a31..0000000
--- a/core/res/res/drawable-hdpi/pickerbox_background.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pickerbox_selected.9.png b/core/res/res/drawable-hdpi/pickerbox_selected.9.png
deleted file mode 100644
index a88ec63..0000000
--- a/core/res/res/drawable-hdpi/pickerbox_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pickerbox_unselected.9.png b/core/res/res/drawable-hdpi/pickerbox_unselected.9.png
deleted file mode 100644
index 9f6b7cb..0000000
--- a/core/res/res/drawable-hdpi/pickerbox_unselected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pickerbox_background.png b/core/res/res/drawable-mdpi/pickerbox_background.png
deleted file mode 100644
index 6494cd8..0000000
--- a/core/res/res/drawable-mdpi/pickerbox_background.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pickerbox_selected.9.png b/core/res/res/drawable-mdpi/pickerbox_selected.9.png
deleted file mode 100644
index d986a31..0000000
--- a/core/res/res/drawable-mdpi/pickerbox_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pickerbox_unselected.9.png b/core/res/res/drawable-mdpi/pickerbox_unselected.9.png
deleted file mode 100644
index 27ec6b9..0000000
--- a/core/res/res/drawable-mdpi/pickerbox_unselected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/pickerbox.xml b/core/res/res/drawable/pickerbox.xml
deleted file mode 100644
index 9cb2436..0000000
--- a/core/res/res/drawable/pickerbox.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/pickerbox_selected" />
- <item android:drawable="@drawable/pickerbox_unselected" />
-</selector>
-
diff --git a/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml b/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml
index 45e96a3..2a23ada 100644
--- a/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml
@@ -16,59 +16,55 @@
** limitations under the License.
*/
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
+ android:orientation="vertical"
android:background="@android:color/background_dark"
- >
+ android:gravity="center_horizontal">
<LinearLayout android:id="@+id/topDisplayGroup"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:orientation="vertical"
- >
+ android:orientation="vertical">
<!-- header text ('Enter Pin Code') -->
<TextView android:id="@+id/headerText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="9dip"
android:gravity="center"
android:lines="2"
- android:textAppearance="?android:attr/textAppearanceLarge"
- />
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
- <RelativeLayout
+ <!-- password entry -->
+ <LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="18dip"
+ android:orientation="horizontal"
android:layout_marginRight="6dip"
android:layout_marginLeft="6dip"
- android:background="@android:drawable/edit_text"
- >
+ android:gravity="center_vertical"
+ android:background="@android:drawable/edit_text">
<!-- displays dots as user enters pin -->
<TextView android:id="@+id/pinDisplay"
- android:layout_width="wrap_content"
- android:layout_height="64dip"
- android:layout_centerInParent="true"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
android:maxLines="1"
android:textAppearance="?android:attr/textAppearanceLargeInverse"
android:textStyle="bold"
android:inputType="textPassword"
- />
+ />
<ImageButton android:id="@+id/backspace"
android:src="@android:drawable/ic_input_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:layout_marginRight="1dip"
- />
- </RelativeLayout>
-
+ android:layout_marginRight="-3dip"
+ android:layout_marginBottom="-3dip"
+ />
+ </LinearLayout>
</LinearLayout>
@@ -78,16 +74,14 @@
android:layout_height="wrap_content"
android:layout_below="@id/topDisplayGroup"
android:layout_marginTop="10dip"
- android:orientation="vertical"
- >
+ android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
- android:orientation="horizontal"
- >
+ android:orientation="horizontal">
<Button android:id="@+id/one"
android:layout_width="0sp"
@@ -125,8 +119,7 @@
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
- android:orientation="horizontal"
- >
+ android:orientation="horizontal">
<Button android:id="@+id/four"
android:layout_width="0sp"
@@ -164,8 +157,7 @@
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
- android:orientation="horizontal"
- >
+ android:orientation="horizontal">
<Button android:id="@+id/seven"
android:layout_width="0sp"
@@ -203,8 +195,7 @@
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
- android:orientation="horizontal"
- >
+ android:orientation="horizontal">
<Button android:id="@+id/ok"
android:layout_width="0sp"
@@ -242,27 +233,33 @@
<!-- end keypad -->
</LinearLayout>
-
- <!-- emergency call button -->
- <Button
- android:id="@+id/emergencyCall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_alignParentBottom="true"
- android:drawableLeft="@android:drawable/ic_emergency"
- android:drawablePadding="8dip"
- android:text="@android:string/lockscreen_emergency_call"
- />
-
<!-- spacer below keypad -->
<View
android:id="@+id/spacerBottom"
android:layout_width="fill_parent"
android:layout_height="1dip"
- android:layout_marginBottom="6dip"
+ android:layout_marginTop="6dip"
android:layout_above="@id/emergencyCall"
- android:background="@android:drawable/divider_horizontal_dark"/>
+ android:background="@android:drawable/divider_horizontal_dark"
+ />
+ <!-- The emergency button should take the rest of the space and be centered vertically -->
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <!-- emergency call button -->
+ <Button
+ android:id="@+id/emergencyCall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawableLeft="@android:drawable/ic_emergency"
+ android:drawablePadding="8dip"
+ android:text="@android:string/lockscreen_emergency_call"
+ />
+ </LinearLayout>
-</RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bc354c5..047115c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -462,10 +462,17 @@
size.</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_restartPackages">restart other applications</string>
+ <string name="permlab_killBackgroundProcesses">kill background processes</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_restartPackages">Allows an application to
- forcibly restart other applications.</string>
+ <string name="permdesc_killBackgroundProcesses">Allows an application to
+ kill background processes of other applications, even if memory
+ isn\'t low.</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_forceStopPackages">force stop other applications</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_forceStopPackages">Allows an application to
+ forcibly stop other 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_forceBack">force application to close</string>
@@ -1139,6 +1146,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_sdcardWrite">Allows an application to write to the SD card.</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_cache_filesystem">access the cache filesystem</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_cache_filesystem">Allows an application to read and write the cache filesystem.</string>
+
<!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
<!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
<string-array name="phoneTypes">
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index b155769..f2b52d9 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -101,6 +101,7 @@
<!-- Standard animations for a non-full-screen window or activity. -->
<style name="Animation.LockScreen">
+ <item name="windowEnterAnimation">@anim/lock_screen_enter</item>
<item name="windowExitAnimation">@anim/lock_screen_exit</item>
</style>