summaryrefslogtreecommitdiffstats
path: root/core/java/com/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/com/android')
-rw-r--r--core/java/com/android/internal/app/ExternalMediaFormatActivity.java114
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl10
-rwxr-xr-xcore/java/com/android/internal/app/IUsageStats.aidl27
-rw-r--r--core/java/com/android/internal/app/UsbStorageStopActivity.java123
-rw-r--r--core/java/com/android/internal/gadget/IGadgetHost.aidl27
-rw-r--r--core/java/com/android/internal/gadget/IGadgetService.aidl26
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java277
-rw-r--r--core/java/com/android/internal/os/HandlerCaller.java13
-rwxr-xr-xcore/java/com/android/internal/os/PkgUsageStats.aidl20
-rwxr-xr-xcore/java/com/android/internal/os/PkgUsageStats.java60
-rw-r--r--core/java/com/android/internal/os/RecoverySystem.java128
-rw-r--r--core/java/com/android/internal/view/IInputConnectionWrapper.java173
-rw-r--r--core/java/com/android/internal/view/IInputContext.aidl8
-rw-r--r--core/java/com/android/internal/view/IInputMethod.aidl6
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl3
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java26
-rw-r--r--core/java/com/android/internal/view/menu/IconMenuItemView.java5
-rw-r--r--core/java/com/android/internal/view/menu/ListMenuItemView.java4
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java316
-rw-r--r--core/java/com/android/internal/widget/SlidingDrawer.java924
20 files changed, 996 insertions, 1294 deletions
diff --git a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
new file mode 100644
index 0000000..000f6c4
--- /dev/null
+++ b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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.app;
+
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IMountService;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.Environment;
+import android.widget.Toast;
+import android.util.Log;
+
+/**
+ * This activity is shown to the user to confirm formatting of external media.
+ * It uses the alert dialog style. It will be launched from a notification, or from settings
+ */
+public class ExternalMediaFormatActivity extends AlertActivity implements DialogInterface.OnClickListener {
+
+ private static final int POSITIVE_BUTTON = AlertDialog.BUTTON1;
+
+ /** Used to detect when the media state changes, in case we need to call finish() */
+ private BroadcastReceiver mStorageReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.d("ExternalMediaFormatActivity", "got action " + action);
+
+ if (action == Intent.ACTION_MEDIA_REMOVED ||
+ action == Intent.ACTION_MEDIA_CHECKING ||
+ action == Intent.ACTION_MEDIA_MOUNTED ||
+ action == Intent.ACTION_MEDIA_SHARED) {
+ finish();
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Log.d("ExternalMediaFormatActivity", "onCreate!");
+ // Set up the "dialog"
+ final AlertController.AlertParams p = mAlertParams;
+ p.mIconId = com.android.internal.R.drawable.stat_sys_warning;
+ p.mTitle = getString(com.android.internal.R.string.extmedia_format_title);
+ p.mMessage = getString(com.android.internal.R.string.extmedia_format_message);
+ p.mPositiveButtonText = getString(com.android.internal.R.string.extmedia_format_button_format);
+ p.mPositiveButtonListener = this;
+ p.mNegativeButtonText = getString(com.android.internal.R.string.cancel);
+ p.mNegativeButtonListener = this;
+ setupAlert();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_MEDIA_REMOVED);
+ filter.addAction(Intent.ACTION_MEDIA_CHECKING);
+ filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
+ filter.addAction(Intent.ACTION_MEDIA_SHARED);
+ registerReceiver(mStorageReceiver, filter);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ unregisterReceiver(mStorageReceiver);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onClick(DialogInterface dialog, int which) {
+
+ if (which == POSITIVE_BUTTON) {
+ IMountService mountService = IMountService.Stub.asInterface(ServiceManager
+ .getService("mount"));
+ if (mountService != null) {
+ try {
+ mountService.formatMedia(Environment.getExternalStorageDirectory().toString());
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ // No matter what, finish the activity
+ finish();
+ }
+}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 434850c..eb232c7 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -22,8 +22,14 @@ interface IBatteryStats {
BatteryStatsImpl getStatistics();
void noteStartWakelock(int uid, String name, int type);
void noteStopWakelock(int uid, String name, int type);
- void noteStartSensor(int uid, int sensor);
- void noteStopSensor(int uid, int sensor);
+ void noteStartSensor(int uid, String name, int sensor);
+ void noteStopSensor(int uid, String name, int sensor);
+ void noteRequestGpsOn(int uid);
+ void noteRequestGpsOff(int uid);
+ void noteStartGps(int uid);
+ void noteStopGps(int uid);
+ void noteScreenOn();
+ void noteScreenOff();
void setOnBattery(boolean onBattery);
long getAwakeTimeBattery();
long getAwakeTimePlugged();
diff --git a/core/java/com/android/internal/app/IUsageStats.aidl b/core/java/com/android/internal/app/IUsageStats.aidl
new file mode 100755
index 0000000..6b053d5
--- /dev/null
+++ b/core/java/com/android/internal/app/IUsageStats.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.app;
+
+import android.content.ComponentName;
+import com.android.internal.os.PkgUsageStats;
+
+interface IUsageStats {
+ void noteResumeComponent(in ComponentName componentName);
+ void notePauseComponent(in ComponentName componentName);
+ PkgUsageStats getPkgUsageStats(in ComponentName componentName);
+ PkgUsageStats[] getAllPkgUsageStats();
+}
diff --git a/core/java/com/android/internal/app/UsbStorageStopActivity.java b/core/java/com/android/internal/app/UsbStorageStopActivity.java
new file mode 100644
index 0000000..30523c4
--- /dev/null
+++ b/core/java/com/android/internal/app/UsbStorageStopActivity.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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.app;
+
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IMountService;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.widget.Toast;
+
+/**
+ * This activity is shown to the user for him/her to disable USB mass storage.
+ * It uses the alert dialog style. It will be launched from a notification.
+ */
+public class UsbStorageStopActivity extends AlertActivity implements DialogInterface.OnClickListener {
+
+ private static final int POSITIVE_BUTTON = AlertDialog.BUTTON1;
+
+ /** Used to detect when the USB cable is unplugged, so we can call finish() */
+ private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction() == Intent.ACTION_BATTERY_CHANGED) {
+ handleBatteryChanged(intent);
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Set up the "dialog"
+ final AlertController.AlertParams p = mAlertParams;
+ p.mIconId = com.android.internal.R.drawable.stat_sys_warning;
+ p.mTitle = getString(com.android.internal.R.string.usb_storage_stop_title);
+ p.mMessage = getString(com.android.internal.R.string.usb_storage_stop_message);
+ p.mPositiveButtonText = getString(com.android.internal.R.string.usb_storage_stop_button_mount);
+ p.mPositiveButtonListener = this;
+ p.mNegativeButtonText = getString(com.android.internal.R.string.usb_storage_stop_button_unmount);
+ p.mNegativeButtonListener = this;
+ setupAlert();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ unregisterReceiver(mBatteryReceiver);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onClick(DialogInterface dialog, int which) {
+
+ if (which == POSITIVE_BUTTON) {
+ stopUsbStorage();
+ }
+
+ // No matter what, finish the activity
+ finish();
+ }
+
+ private void stopUsbStorage() {
+ IMountService mountService = IMountService.Stub.asInterface(ServiceManager
+ .getService("mount"));
+ if (mountService == null) {
+ showStoppingError();
+ return;
+ }
+
+ try {
+ mountService.setMassStorageEnabled(false);
+ } catch (RemoteException e) {
+ showStoppingError();
+ return;
+ }
+ }
+
+ private void handleBatteryChanged(Intent intent) {
+ int pluggedType = intent.getIntExtra("plugged", 0);
+ if (pluggedType == 0) {
+ // It was disconnected from the plug, so finish
+ finish();
+ }
+ }
+
+ private void showStoppingError() {
+ Toast.makeText(this, com.android.internal.R.string.usb_storage_stop_error_message,
+ Toast.LENGTH_LONG).show();
+ }
+
+}
diff --git a/core/java/com/android/internal/gadget/IGadgetHost.aidl b/core/java/com/android/internal/gadget/IGadgetHost.aidl
new file mode 100644
index 0000000..a5b8654
--- /dev/null
+++ b/core/java/com/android/internal/gadget/IGadgetHost.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.gadget;
+
+import android.content.ComponentName;
+import android.gadget.GadgetInfo;
+import android.widget.RemoteViews;
+
+/** {@hide} */
+oneway interface IGadgetHost {
+ void updateGadget(int gadgetId, in RemoteViews views);
+}
+
diff --git a/core/java/com/android/internal/gadget/IGadgetService.aidl b/core/java/com/android/internal/gadget/IGadgetService.aidl
index 6f9af04..1b3946f 100644
--- a/core/java/com/android/internal/gadget/IGadgetService.aidl
+++ b/core/java/com/android/internal/gadget/IGadgetService.aidl
@@ -18,12 +18,32 @@ package com.android.internal.gadget;
import android.content.ComponentName;
import android.gadget.GadgetInfo;
+import com.android.internal.gadget.IGadgetHost;
+import android.widget.RemoteViews;
/** {@hide} */
interface IGadgetService {
- int allocateGadgetId(String hostPackage);
+
+ //
+ // for GadgetHost
+ //
+ int[] startListening(IGadgetHost host, String packageName, int hostId,
+ out List<RemoteViews> updatedViews);
+ void stopListening(int hostId);
+ int allocateGadgetId(String packageName, int hostId);
void deleteGadgetId(int gadgetId);
- void bindGadgetId(int gadgetId, in ComponentName provider);
- GadgetInfo getGadgetInfo(int gadgetId);
+ void deleteHost(int hostId);
+ void deleteAllHosts();
+ RemoteViews getGadgetViews(int gadgetId);
+
+ //
+ // for GadgetManager
+ //
+ void updateGadgetIds(in int[] gadgetIds, in RemoteViews views);
+ void updateGadgetProvider(in ComponentName provider, in RemoteViews views);
List<GadgetInfo> getInstalledProviders();
+ GadgetInfo getGadgetInfo(int gadgetId);
+ void bindGadgetId(int gadgetId, in ComponentName provider);
+
}
+
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8912960..cbb65dc 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -17,6 +17,7 @@
package com.android.internal.os;
import android.os.BatteryStats;
+import android.os.NetStat;
import android.os.Parcel;
import android.os.ParcelFormatException;
import android.os.Parcelable;
@@ -28,9 +29,9 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
/**
@@ -39,12 +40,14 @@ import java.util.Map;
* otherwise.
*/
public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
+
+ private static final String TAG = "BatteryStatsImpl";
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 13;
+ private static final int VERSION = 15;
private final File mFile;
private final File mBackupFile;
@@ -77,7 +80,11 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
long mRealtime;
long mRealtimeStart;
long mLastRealtime;
-
+
+ boolean mScreenOn;
+ long mLastScreenOnTimeMillis;
+ long mBatteryScreenOnTimeMillis;
+ long mPluggedScreenOnTimeMillis;
/**
* These provide time bases that discount the time the device is plugged
* in to power.
@@ -87,6 +94,11 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
long mTrackBatteryUptimeStart;
long mTrackBatteryPastRealtime;
long mTrackBatteryRealtimeStart;
+
+ long mUnpluggedBatteryUptime;
+ long mUnpluggedBatteryRealtime;
+
+ HashSet<Integer> mGpsRequesters = new HashSet<Integer>();
long mLastWriteTime = 0; // Milliseconds
@@ -255,14 +267,13 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
long realtime = SystemClock.elapsedRealtime() * 1000;
long heldTime = stats.getBatteryUptimeLocked(realtime) - mUpdateTime;
if (heldTime > 0) {
- mTotalTime += (heldTime * 1000) / mCount;
+ mTotalTime += heldTime / mCount;
}
mUpdateTime = stats.getBatteryUptimeLocked(realtime);
}
private long computeRunTimeLocked(long curBatteryUptime) {
- return mTotalTime +
- (mNesting > 0 ? ((curBatteryUptime * 1000) - mUpdateTime) / mCount : 0);
+ return mTotalTime + (mNesting > 0 ? (curBatteryUptime - mUpdateTime) / mCount : 0);
}
void writeSummaryFromParcelLocked(Parcel out, long curBatteryUptime) {
@@ -284,6 +295,15 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
}
}
+ public void unplugTcpCounters() {
+ final int NU = mUidStats.size();
+ for (int iu = 0; iu < NU; iu++) {
+ Uid u = mUidStats.valueAt(iu);
+ u.mTcpBytesReceivedAtLastUnplug = u.getTcpBytesReceived(STATS_TOTAL);
+ u.mTcpBytesSentAtLastUnplug = u.getTcpBytesSent(STATS_TOTAL);
+ }
+ }
+
public void unplugTimers() {
ArrayList<Timer> timers;
@@ -305,6 +325,69 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
}
}
+ public void noteStartGps(int uid) {
+ mGpsRequesters.add(uid);
+ mUidStats.get(uid).noteStartGps();
+ }
+
+ public void noteStopGps(int uid) {
+ mGpsRequesters.remove(uid);
+ mUidStats.get(uid).noteStopGps();
+ }
+
+ public void noteRequestGpsOn(int uid) {
+ mGpsRequesters.add(uid);
+ mUidStats.get(uid).noteStartGps();
+ }
+
+ public void noteRequestGpsOff(int uid) {
+ mGpsRequesters.remove(uid);
+ mUidStats.get(uid).noteStopGps();
+ }
+
+ /**
+ * When the device screen or battery state changes, update the appropriate "screen on time"
+ * counter.
+ */
+ private void updateScreenOnTime(boolean screenOn) {
+ if (!mScreenOn) {
+ Log.w(TAG, "updateScreenOnTime without mScreenOn, ignored");
+ return;
+ }
+ long now = SystemClock.elapsedRealtime();
+ long elapsed = now - mLastScreenOnTimeMillis;
+ if (mOnBattery) {
+ mBatteryScreenOnTimeMillis += elapsed;
+ } else {
+ mPluggedScreenOnTimeMillis += elapsed;
+ }
+ if (screenOn) {
+ mLastScreenOnTimeMillis = now;
+ }
+ }
+
+ public void noteScreenOn() {
+ mScreenOn = true;
+ mLastScreenOnTimeMillis = SystemClock.elapsedRealtime();
+ }
+
+ public void noteScreenOff() {
+ if (!mScreenOn) {
+ Log.w(TAG, "noteScreenOff without mScreenOn, ignored");
+ return;
+ }
+ updateScreenOnTime(false);
+ mScreenOn = false;
+ }
+
+ @Override public long getBatteryScreenOnTime() {
+ return mBatteryScreenOnTimeMillis;
+ }
+
+ @Override public long getPluggedScreenOnTime() {
+ return mPluggedScreenOnTimeMillis;
+ }
+
@Override
public SparseArray<? extends BatteryStats.Uid> getUidStats() {
return mUidStats;
@@ -314,6 +397,14 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
* The statistics associated with a particular uid.
*/
public final class Uid extends BatteryStats.Uid {
+
+ final int mUid;
+ long mLoadedTcpBytesReceived;
+ long mLoadedTcpBytesSent;
+ long mTcpBytesReceivedAtLastUnplug;
+ long mTcpBytesSentAtLastUnplug;
+
+ private final byte[] mBuf = new byte[16];
/**
* The statistics we have collected for this uid's wake locks.
@@ -334,6 +425,10 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
* The statistics we have collected for this uid's processes.
*/
final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
+
+ public Uid(int uid) {
+ mUid = uid;
+ }
@Override
public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
@@ -354,6 +449,42 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
return mPackageStats;
}
+
+ public int getUid() {
+ return mUid;
+ }
+
+ public long getTcpBytesReceived(int which) {
+ long current = NetStat.getUidRxBytes(mUid);
+
+ if (which == STATS_CURRENT) {
+ return current;
+ } else if (which == STATS_LAST) {
+ return mLoadedTcpBytesReceived;
+ } else if (which == STATS_UNPLUGGED) {
+ return current - mTcpBytesReceivedAtLastUnplug;
+ } else if (which == STATS_TOTAL) {
+ return mLoadedTcpBytesReceived + current;
+ } else {
+ throw new IllegalArgumentException("which = " + which);
+ }
+ }
+
+ public long getTcpBytesSent(int which) {
+ long current = NetStat.getUidTxBytes(mUid);
+
+ if (which == STATS_CURRENT) {
+ return current;
+ } else if (which == STATS_LAST) {
+ return mLoadedTcpBytesSent;
+ } else if (which == STATS_UNPLUGGED) {
+ return current - mTcpBytesSentAtLastUnplug;
+ } else if (which == STATS_TOTAL) {
+ return mLoadedTcpBytesSent + current;
+ } else {
+ throw new IllegalArgumentException("which = " + which);
+ }
+ }
void writeToParcelLocked(Parcel out) {
out.writeInt(mWakelockStats.size());
@@ -366,6 +497,7 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
out.writeInt(mSensorStats.size());
for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
out.writeInt(sensorEntry.getKey());
+ out.writeString(sensorEntry.getValue().getName());
Uid.Sensor sensor = sensorEntry.getValue();
sensor.writeToParcelLocked(out);
}
@@ -383,6 +515,11 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
Uid.Pkg pkg = pkgEntry.getValue();
pkg.writeToParcelLocked(out);
}
+
+ out.writeLong(mLoadedTcpBytesReceived);
+ out.writeLong(mLoadedTcpBytesSent);
+ out.writeLong(mTcpBytesReceivedAtLastUnplug);
+ out.writeLong(mTcpBytesSentAtLastUnplug);
}
void readFromParcelLocked(Parcel in) {
@@ -399,7 +536,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mSensorStats.clear();
for (int k = 0; k < numSensors; k++) {
int sensorNumber = in.readInt();
- Uid.Sensor sensor = new Sensor();
+ String name = in.readString();
+ Uid.Sensor sensor = new Sensor(name);
sensor.readFromParcelLocked(in);
mSensorStats.put(sensorNumber, sensor);
}
@@ -421,6 +559,11 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
pkg.readFromParcelLocked(in);
mPackageStats.put(packageName, pkg);
}
+
+ mLoadedTcpBytesReceived = in.readLong();
+ mLoadedTcpBytesSent = in.readLong();
+ mTcpBytesReceivedAtLastUnplug = in.readLong();
+ mTcpBytesSentAtLastUnplug = in.readLong();
}
/**
@@ -499,7 +642,13 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
}
public final class Sensor extends BatteryStats.Uid.Sensor {
+ static final int GPS = -10000; // Treat GPS as a sensor
+ final String mName;
Timer sensorTime;
+
+ public Sensor(String name) {
+ mName = name;
+ }
private Timer readTimerFromParcel(Parcel in) {
if (in.readInt() == 0) {
@@ -530,6 +679,10 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
public Timer getSensorTime() {
return sensorTime;
}
+
+ public String getName() {
+ return mName;
+ }
}
/**
@@ -1039,19 +1192,19 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
}
}
- public Timer getSensorTimerLocked(int sensor, boolean create) {
+ public Timer getSensorTimerLocked(String name, int sensor, boolean create) {
Integer sId = Integer.valueOf(sensor);
Sensor se = mSensorStats.get(sId);
if (se == null) {
if (!create) {
return null;
}
- se = new Sensor();
+ se = new Sensor(name);
mSensorStats.put(sId, se);
}
Timer t = se.sensorTime;
if (t == null) {
- t = new Timer(0, mSensorTimers);
+ t = new Timer(BatteryStats.SENSOR, mSensorTimers);
se.sensorTime = t;
}
return t;
@@ -1071,20 +1224,34 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
}
}
- public void noteStartSensor(int sensor) {
- Timer t = getSensorTimerLocked(sensor, true);
+ public void noteStartSensor(String name, int sensor) {
+ Timer t = getSensorTimerLocked(name, sensor, true);
if (t != null) {
t.startRunningLocked(BatteryStatsImpl.this);
}
}
- public void noteStopSensor(int sensor) {
+ public void noteStopSensor(String name, int sensor) {
// Don't create a timer if one doesn't already exist
- Timer t = getSensorTimerLocked(sensor, false);
+ Timer t = getSensorTimerLocked(name, sensor, false);
if (t != null) {
t.stopRunningLocked(BatteryStatsImpl.this);
}
}
+
+ public void noteStartGps() {
+ Timer t = getSensorTimerLocked("GPS", Sensor.GPS, true);
+ if (t != null) {
+ t.startRunningLocked(BatteryStatsImpl.this);
+ }
+ }
+
+ public void noteStopGps() {
+ Timer t = getSensorTimerLocked("GPS", Sensor.GPS, false);
+ if (t != null) {
+ t.stopRunningLocked(BatteryStatsImpl.this);
+ }
+ }
public BatteryStatsImpl getBatteryStats() {
return BatteryStatsImpl.this;
@@ -1100,6 +1267,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mTrackBatteryPastRealtime = 0;
mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
+
+ mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
+ mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
}
public BatteryStatsImpl(Parcel p) {
@@ -1119,13 +1289,21 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
public void setOnBattery(boolean onBattery) {
synchronized(this) {
if (mOnBattery != onBattery) {
+ if (mScreenOn) {
+ updateScreenOnTime(true);
+ }
+
long uptime = SystemClock.uptimeMillis() * 1000;
long mSecRealtime = SystemClock.elapsedRealtime();
long realtime = mSecRealtime * 1000;
if (onBattery) {
- mTrackBatteryUptimeStart = uptime;
- mTrackBatteryRealtimeStart = realtime;
+ mTrackBatteryUptimeStart = getBatteryUptime(uptime);
+ mTrackBatteryRealtimeStart = getBatteryRealtime(realtime);
+ unplugTcpCounters();
unplugTimers();
+
+ mUnpluggedBatteryUptime = getBatteryUptime(uptime);
+ mUnpluggedBatteryRealtime = getBatteryRealtime(realtime);
} else {
mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
@@ -1172,14 +1350,16 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
@Override
public long computeBatteryUptime(long curTime, int which) {
+ long uptime = getBatteryUptime(curTime);
switch (which) {
case STATS_TOTAL:
- return mBatteryUptime + getBatteryUptime(curTime);
+ return mBatteryUptime + uptime;
case STATS_LAST:
return mBatteryLastUptime;
case STATS_CURRENT:
+ return uptime;
case STATS_UNPLUGGED:
- return getBatteryUptime(curTime);
+ return uptime - mUnpluggedBatteryUptime;
}
return 0;
}
@@ -1192,8 +1372,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
case STATS_LAST:
return mBatteryLastRealtime;
case STATS_CURRENT:
- case STATS_UNPLUGGED:
return getBatteryRealtimeLocked(curTime);
+ case STATS_UNPLUGGED:
+ return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
}
return 0;
}
@@ -1234,7 +1415,7 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
public Uid getUidStatsLocked(int uid) {
Uid u = mUidStats.get(uid);
if (u == null) {
- u = new Uid();
+ u = new Uid(uid);
mUidStats.put(uid, u);
}
return u;
@@ -1246,7 +1427,7 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
public void removeUidStatsLocked(int uid) {
mUidStats.remove(uid);
}
-
+
/**
* Retrieve the statistics object for a particular process, creating
* if needed.
@@ -1388,15 +1569,21 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mRealtime = in.readLong();
mLastRealtime = in.readLong();
mStartCount++;
+
+ if (version >= 14) {
+ mBatteryScreenOnTimeMillis = in.readLong();
+ mPluggedScreenOnTimeMillis = in.readLong();
+ mScreenOn = false;
+ }
final int NU = in.readInt();
- for (int iu=0; iu<NU; iu++) {
+ for (int iu = 0; iu < NU; iu++) {
int uid = in.readInt();
- Uid u = new Uid();
+ Uid u = new Uid(uid);
mUidStats.put(uid, u);
int NW = in.readInt();
- for (int iw=0; iw<NW; iw++) {
+ for (int iw = 0; iw < NW; iw++) {
String wlName = in.readString();
if (in.readInt() != 0) {
u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
@@ -1411,16 +1598,21 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
if (version >= 12) {
int NSE = in.readInt();
- for (int is=0; is<NSE; is++) {
+ for (int is = 0; is < NSE; is++) {
int seNumber = in.readInt();
+ String seName = "<unknown>";
+ if (version >= 14) {
+ seName = in.readString();
+ }
if (in.readInt() != 0) {
- u.getSensorTimerLocked(seNumber, true).readSummaryFromParcelLocked(in);
+ u.getSensorTimerLocked(seName, seNumber, true)
+ .readSummaryFromParcelLocked(in);
}
}
}
int NP = in.readInt();
- for (int ip=0; ip<NP; ip++) {
+ for (int ip = 0; ip < NP; ip++) {
String procName = in.readString();
Uid.Proc p = u.getProcessStatsLocked(procName);
p.mUserTime = p.mLoadedUserTime = in.readLong();
@@ -1432,13 +1624,13 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
}
NP = in.readInt();
- for (int ip=0; ip<NP; ip++) {
+ for (int ip = 0; ip < NP; ip++) {
String pkgName = in.readString();
Uid.Pkg p = u.getPackageStatsLocked(pkgName);
p.mWakeups = p.mLoadedWakeups = in.readInt();
p.mLastWakeups = in.readInt();
final int NS = in.readInt();
- for (int is=0; is<NS; is++) {
+ for (int is = 0; is < NS; is++) {
String servName = in.readString();
Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
s.mStartTime = s.mLoadedStartTime = in.readLong();
@@ -1449,6 +1641,11 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
s.mLastLaunches = in.readInt();
}
}
+
+ if (version >= 14) {
+ u.mLoadedTcpBytesReceived = in.readLong();
+ u.mLoadedTcpBytesSent = in.readLong();
+ }
}
}
@@ -1474,10 +1671,13 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT));
out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL));
out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT));
+
+ out.writeLong(mBatteryScreenOnTimeMillis);
+ out.writeLong(mPluggedScreenOnTimeMillis);
final int NU = mUidStats.size();
out.writeInt(NU);
- for (int iu=0; iu<NU; iu++) {
+ for (int iu = 0; iu < NU; iu++) {
out.writeInt(mUidStats.keyAt(iu));
Uid u = mUidStats.valueAt(iu);
@@ -1516,6 +1716,7 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
: u.mSensorStats.entrySet()) {
out.writeInt(ent.getKey());
Uid.Sensor se = ent.getValue();
+ out.writeString(se.getName());
if (se.sensorTime != null) {
out.writeInt(1);
se.sensorTime.writeSummaryFromParcelLocked(out, NOW);
@@ -1568,6 +1769,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
}
}
}
+
+ out.writeLong(u.getTcpBytesReceived(STATS_TOTAL));
+ out.writeLong(u.getTcpBytesSent(STATS_TOTAL));
}
}
@@ -1586,6 +1790,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mBatteryLastUptime = in.readLong();
mBatteryRealtime = in.readLong();
mBatteryLastRealtime = in.readLong();
+ mBatteryScreenOnTimeMillis = in.readLong();
+ mPluggedScreenOnTimeMillis = in.readLong();
+ mScreenOn = false;
mUptime = in.readLong();
mUptimeStart = in.readLong();
mLastUptime = in.readLong();
@@ -1606,10 +1813,10 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
int numUids = in.readInt();
mUidStats.clear();
for (int i = 0; i < numUids; i++) {
- int key = in.readInt();
- Uid uid = new Uid();
- uid.readFromParcelLocked(in);
- mUidStats.append(key, uid);
+ int uid = in.readInt();
+ Uid u = new Uid(uid);
+ u.readFromParcelLocked(in);
+ mUidStats.append(uid, u);
}
}
@@ -1625,6 +1832,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
out.writeLong(mBatteryLastUptime);
out.writeLong(mBatteryRealtime);
out.writeLong(mBatteryLastRealtime);
+ out.writeLong(mBatteryScreenOnTimeMillis);
+ out.writeLong(mPluggedScreenOnTimeMillis);
out.writeLong(mUptime);
out.writeLong(mUptimeStart);
out.writeLong(mLastUptime);
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 1ec74a1..bab1e21 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -21,7 +21,8 @@ public class HandlerCaller {
public Object arg1;
public Object arg2;
- Object arg3;
+ public Object arg3;
+ public Object arg4;
public int argi1;
public int argi2;
public int argi3;
@@ -149,6 +150,16 @@ public class HandlerCaller {
return mH.obtainMessage(what, 0, 0, args);
}
+ public Message obtainMessageOOOO(int what, Object arg1, Object arg2,
+ Object arg3, Object arg4) {
+ SomeArgs args = obtainArgs();
+ args.arg1 = arg1;
+ args.arg2 = arg2;
+ args.arg3 = arg3;
+ args.arg4 = arg4;
+ return mH.obtainMessage(what, 0, 0, args);
+ }
+
public Message obtainMessageIIII(int what, int arg1, int arg2,
int arg3, int arg4) {
SomeArgs args = obtainArgs();
diff --git a/core/java/com/android/internal/os/PkgUsageStats.aidl b/core/java/com/android/internal/os/PkgUsageStats.aidl
new file mode 100755
index 0000000..8305271
--- /dev/null
+++ b/core/java/com/android/internal/os/PkgUsageStats.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/content/Intent.aidl
+**
+** 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.
+*/
+
+package com.android.internal.os;
+
+parcelable PkgUsageStats;
diff --git a/core/java/com/android/internal/os/PkgUsageStats.java b/core/java/com/android/internal/os/PkgUsageStats.java
new file mode 100755
index 0000000..e847878
--- /dev/null
+++ b/core/java/com/android/internal/os/PkgUsageStats.java
@@ -0,0 +1,60 @@
+package com.android.internal.os;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * implementation of PkgUsageStats associated with an
+ * application package.
+ * @hide
+ */
+public class PkgUsageStats implements Parcelable {
+ public String packageName;
+ public int launchCount;
+ public long usageTime;
+
+ public static final Parcelable.Creator<PkgUsageStats> CREATOR
+ = new Parcelable.Creator<PkgUsageStats>() {
+ public PkgUsageStats createFromParcel(Parcel in) {
+ return new PkgUsageStats(in);
+ }
+
+ public PkgUsageStats[] newArray(int size) {
+ return new PkgUsageStats[size];
+ }
+ };
+
+ public String toString() {
+ return "PkgUsageStats{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + packageName + "}";
+ }
+
+ public PkgUsageStats(String pkgName, int count, long time) {
+ packageName = pkgName;
+ launchCount = count;
+ usageTime = time;
+ }
+
+ public PkgUsageStats(Parcel source) {
+ packageName = source.readString();
+ launchCount = source.readInt();
+ usageTime = source.readLong();
+ }
+
+ public PkgUsageStats(PkgUsageStats pStats) {
+ packageName = pStats.packageName;
+ launchCount = pStats.launchCount;
+ usageTime = pStats.usageTime;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int parcelableFlags){
+ dest.writeString(packageName);
+ dest.writeInt(launchCount);
+ dest.writeLong(usageTime);
+ }
+}
diff --git a/core/java/com/android/internal/os/RecoverySystem.java b/core/java/com/android/internal/os/RecoverySystem.java
new file mode 100644
index 0000000..c938610
--- /dev/null
+++ b/core/java/com/android/internal/os/RecoverySystem.java
@@ -0,0 +1,128 @@
+/*
+ * 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 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/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 011e944..b0b00b2 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -13,6 +13,8 @@ import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
+import java.lang.ref.WeakReference;
+
public class IInputConnectionWrapper extends IInputContext.Stub {
static final String TAG = "IInputConnectionWrapper";
@@ -22,6 +24,8 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
private static final int DO_GET_EXTRACTED_TEXT = 40;
private static final int DO_COMMIT_TEXT = 50;
private static final int DO_COMMIT_COMPLETION = 55;
+ private static final int DO_SET_SELECTION = 57;
+ private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 58;
private static final int DO_SET_COMPOSING_TEXT = 60;
private static final int DO_FINISH_COMPOSING_TEXT = 65;
private static final int DO_SEND_KEY_EVENT = 70;
@@ -33,7 +37,7 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
private static final int DO_CLEAR_META_KEY_STATES = 130;
- private InputConnection mInputConnection;
+ private WeakReference<InputConnection> mInputConnection;
private Looper mMainLooper;
private Handler mH;
@@ -57,17 +61,21 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
}
public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
- mInputConnection = conn;
+ mInputConnection = new WeakReference<InputConnection>(conn);
mMainLooper = mainLooper;
mH = new MyHandler(mMainLooper);
}
- public void getTextAfterCursor(int length, int seq, IInputContextCallback callback) {
- dispatchMessage(obtainMessageISC(DO_GET_TEXT_AFTER_CURSOR, length, seq, callback));
+ public boolean isActive() {
+ return true;
+ }
+
+ public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
+ dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
}
- public void getTextBeforeCursor(int length, int seq, IInputContextCallback callback) {
- dispatchMessage(obtainMessageISC(DO_GET_TEXT_BEFORE_CURSOR, length, seq, callback));
+ public void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback) {
+ dispatchMessage(obtainMessageIISC(DO_GET_TEXT_BEFORE_CURSOR, length, flags, seq, callback));
}
public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
@@ -88,6 +96,14 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
}
+ public void setSelection(int start, int end) {
+ dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
+ }
+
+ public void performContextMenuAction(int id) {
+ dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
+ }
+
public void setComposingText(CharSequence text, int newCursorPosition) {
dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
}
@@ -147,8 +163,14 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
case DO_GET_TEXT_AFTER_CURSOR: {
SomeArgs args = (SomeArgs)msg.obj;
try {
- args.callback.setTextAfterCursor(mInputConnection.getTextAfterCursor(msg.arg1),
- args.seq);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
+ args.callback.setTextAfterCursor(null, args.seq);
+ return;
+ }
+ args.callback.setTextAfterCursor(ic.getTextAfterCursor(
+ msg.arg1, msg.arg2), args.seq);
} catch (RemoteException e) {
Log.w(TAG, "Got RemoteException calling setTextAfterCursor", e);
}
@@ -157,8 +179,14 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
case DO_GET_TEXT_BEFORE_CURSOR: {
SomeArgs args = (SomeArgs)msg.obj;
try {
- args.callback.setTextBeforeCursor(mInputConnection.getTextBeforeCursor(msg.arg1),
- args.seq);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
+ args.callback.setTextBeforeCursor(null, args.seq);
+ return;
+ }
+ args.callback.setTextBeforeCursor(ic.getTextBeforeCursor(
+ msg.arg1, msg.arg2), args.seq);
} catch (RemoteException e) {
Log.w(TAG, "Got RemoteException calling setTextBeforeCursor", e);
}
@@ -167,7 +195,13 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
case DO_GET_CURSOR_CAPS_MODE: {
SomeArgs args = (SomeArgs)msg.obj;
try {
- args.callback.setCursorCapsMode(mInputConnection.getCursorCapsMode(msg.arg1),
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
+ args.callback.setCursorCapsMode(0, args.seq);
+ return;
+ }
+ args.callback.setCursorCapsMode(ic.getCursorCapsMode(msg.arg1),
args.seq);
} catch (RemoteException e) {
Log.w(TAG, "Got RemoteException calling setCursorCapsMode", e);
@@ -177,7 +211,13 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
case DO_GET_EXTRACTED_TEXT: {
SomeArgs args = (SomeArgs)msg.obj;
try {
- args.callback.setExtractedText(mInputConnection.getExtractedText(
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getExtractedText on inactive InputConnection");
+ args.callback.setExtractedText(null, args.seq);
+ return;
+ }
+ args.callback.setExtractedText(ic.getExtractedText(
(ExtractedTextRequest)args.arg1, msg.arg1), args.seq);
} catch (RemoteException e) {
Log.w(TAG, "Got RemoteException calling setExtractedText", e);
@@ -185,52 +225,130 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
return;
}
case DO_COMMIT_TEXT: {
- mInputConnection.commitText((CharSequence)msg.obj, msg.arg1);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitText on inactive InputConnection");
+ return;
+ }
+ ic.commitText((CharSequence)msg.obj, msg.arg1);
+ return;
+ }
+ case DO_SET_SELECTION: {
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "setSelection on inactive InputConnection");
+ return;
+ }
+ ic.setSelection(msg.arg1, msg.arg2);
+ return;
+ }
+ case DO_PERFORM_CONTEXT_MENU_ACTION: {
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "performContextMenuAction on inactive InputConnection");
+ return;
+ }
+ ic.performContextMenuAction(msg.arg1);
return;
}
case DO_COMMIT_COMPLETION: {
- mInputConnection.commitCompletion((CompletionInfo)msg.obj);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitCompletion on inactive InputConnection");
+ return;
+ }
+ ic.commitCompletion((CompletionInfo)msg.obj);
return;
}
case DO_SET_COMPOSING_TEXT: {
- mInputConnection.setComposingText((CharSequence)msg.obj, msg.arg1);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "setComposingText on inactive InputConnection");
+ return;
+ }
+ ic.setComposingText((CharSequence)msg.obj, msg.arg1);
return;
}
case DO_FINISH_COMPOSING_TEXT: {
- mInputConnection.finishComposingText();
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "finishComposingText on inactive InputConnection");
+ return;
+ }
+ ic.finishComposingText();
return;
}
case DO_SEND_KEY_EVENT: {
- mInputConnection.sendKeyEvent((KeyEvent)msg.obj);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "sendKeyEvent on inactive InputConnection");
+ return;
+ }
+ ic.sendKeyEvent((KeyEvent)msg.obj);
return;
}
case DO_CLEAR_META_KEY_STATES: {
- mInputConnection.clearMetaKeyStates(msg.arg1);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
+ return;
+ }
+ ic.clearMetaKeyStates(msg.arg1);
return;
}
case DO_DELETE_SURROUNDING_TEXT: {
- mInputConnection.deleteSurroundingText(msg.arg1, msg.arg2);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
+ return;
+ }
+ ic.deleteSurroundingText(msg.arg1, msg.arg2);
return;
}
case DO_BEGIN_BATCH_EDIT: {
- mInputConnection.beginBatchEdit();
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "beginBatchEdit on inactive InputConnection");
+ return;
+ }
+ ic.beginBatchEdit();
return;
}
case DO_END_BATCH_EDIT: {
- mInputConnection.beginBatchEdit();
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "endBatchEdit on inactive InputConnection");
+ return;
+ }
+ ic.endBatchEdit();
return;
}
case DO_HIDE_STATUS_ICON: {
- mInputConnection.hideStatusIcon();
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "hideStatusIcon on inactive InputConnection");
+ return;
+ }
+ ic.hideStatusIcon();
return;
}
case DO_SHOW_STATUS_ICON: {
- mInputConnection.showStatusIcon((String)msg.obj, msg.arg1);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "showStatusIcon on inactive InputConnection");
+ return;
+ }
+ ic.showStatusIcon((String)msg.obj, msg.arg1);
return;
}
case DO_PERFORM_PRIVATE_COMMAND: {
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "performPrivateCommand on inactive InputConnection");
+ return;
+ }
SomeArgs args = (SomeArgs)msg.obj;
- mInputConnection.performPrivateCommand((String)args.arg1,
+ ic.performPrivateCommand((String)args.arg1,
(Bundle)args.arg2);
return;
}
@@ -257,6 +375,13 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
return mH.obtainMessage(what, arg1, 0, args);
}
+ Message obtainMessageIISC(int what, int arg1, int arg2, int seq, IInputContextCallback callback) {
+ SomeArgs args = new SomeArgs();
+ args.callback = callback;
+ args.seq = seq;
+ return mH.obtainMessage(what, arg1, arg2, args);
+ }
+
Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq,
IInputContextCallback callback) {
SomeArgs args = new SomeArgs();
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index b048ce2..7cc8ada 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -29,9 +29,9 @@ import com.android.internal.view.IInputContextCallback;
* {@hide}
*/
oneway interface IInputContext {
- void getTextBeforeCursor(int length, int seq, IInputContextCallback callback);
+ void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback);
- void getTextAfterCursor(int length, int seq, IInputContextCallback callback);
+ void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback);
void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback);
@@ -48,6 +48,10 @@ import com.android.internal.view.IInputContextCallback;
void commitCompletion(in CompletionInfo completion);
+ void setSelection(int start, int end);
+
+ void performContextMenuAction(int id);
+
void beginBatchEdit();
void endBatchEdit();
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index f650713..9b00402 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -38,9 +38,9 @@ oneway interface IInputMethod {
void unbindInput();
- void startInput(in EditorInfo attribute);
+ void startInput(in IInputContext inputContext, in EditorInfo attribute);
- void restartInput(in EditorInfo attribute);
+ void restartInput(in IInputContext inputContext, in EditorInfo attribute);
void createSession(IInputMethodCallback callback);
@@ -48,7 +48,7 @@ oneway interface IInputMethod {
void revokeSession(IInputMethodSession session);
- void showSoftInput(boolean explicit);
+ void showSoftInput(int flags);
void hideSoftInput();
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 2a15bdb..2f5cd14 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -35,7 +35,8 @@ interface IInputMethodManager {
void removeClient(in IInputMethodClient client);
InputBindResult startInput(in IInputMethodClient client,
- in EditorInfo attribute, boolean initial, boolean needResult);
+ IInputContext inputContext, in EditorInfo attribute,
+ boolean initial, boolean needResult);
void finishInput(in IInputMethodClient client);
void showSoftInput(in IInputMethodClient client, int flags);
void hideSoftInput(in IInputMethodClient client, int flags);
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index a9ba5f6..af4ad25 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -151,11 +151,11 @@ public class InputConnectionWrapper implements InputConnection {
mIInputContext = inputContext;
}
- public CharSequence getTextAfterCursor(int length) {
+ public CharSequence getTextAfterCursor(int length, int flags) {
CharSequence value = null;
try {
InputContextCallback callback = InputContextCallback.getInstance();
- mIInputContext.getTextAfterCursor(length, callback.mSeq, callback);
+ mIInputContext.getTextAfterCursor(length, flags, callback.mSeq, callback);
synchronized (callback) {
callback.waitForResultLocked();
if (callback.mHaveValue) {
@@ -169,11 +169,11 @@ public class InputConnectionWrapper implements InputConnection {
return value;
}
- public CharSequence getTextBeforeCursor(int length) {
+ public CharSequence getTextBeforeCursor(int length, int flags) {
CharSequence value = null;
try {
InputContextCallback callback = InputContextCallback.getInstance();
- mIInputContext.getTextBeforeCursor(length, callback.mSeq, callback);
+ mIInputContext.getTextBeforeCursor(length, flags, callback.mSeq, callback);
synchronized (callback) {
callback.waitForResultLocked();
if (callback.mHaveValue) {
@@ -241,6 +241,24 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ public boolean setSelection(int start, int end) {
+ try {
+ mIInputContext.setSelection(start, end);
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ public boolean performContextMenuAction(int id) {
+ try {
+ mIInputContext.performContextMenuAction(id);
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
public boolean setComposingText(CharSequence text, int newCursorPosition) {
try {
mIInputContext.setComposingText(text, newCursorPosition);
diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java
index 558a4c3..9e1f2ae 100644
--- a/core/java/com/android/internal/view/menu/IconMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java
@@ -142,9 +142,6 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie
}
void setCaptionMode(boolean shortcut) {
-
- mShortcutCaptionMode = shortcut && (mItemData.shouldShowShortcut());
-
/*
* If there is no item model, don't do any of the below (for example,
* the 'More' item doesn't have a model)
@@ -153,6 +150,8 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie
return;
}
+ mShortcutCaptionMode = shortcut && (mItemData.shouldShowShortcut());
+
CharSequence text = mItemData.getTitleForItemView(this);
if (mShortcutCaptionMode) {
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index 32513cd..e155875 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -220,7 +220,7 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
mRadioButton =
(RadioButton) inflater.inflate(com.android.internal.R.layout.list_menu_item_radio,
this, false);
- addView(mRadioButton, 0);
+ addView(mRadioButton);
}
private void insertCheckBox() {
@@ -228,7 +228,7 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
mCheckBox =
(CheckBox) inflater.inflate(com.android.internal.R.layout.list_menu_item_checkbox,
this, false);
- addView(mCheckBox, 0);
+ addView(mCheckBox);
}
public boolean prefersCondensedTitle() {
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index a2673a5..648d944 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -16,175 +16,74 @@
package com.android.internal.widget;
-import android.content.res.TypedArray;
import android.os.Bundle;
-import android.os.Handler;
import android.text.Editable;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.TextUtils;
import android.text.method.KeyListener;
import android.util.Log;
-import android.util.LogPrinter;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.widget.TextView;
-class ComposingText {
-}
-
public class EditableInputConnection extends BaseInputConnection {
private static final boolean DEBUG = false;
private static final String TAG = "EditableInputConnection";
- public static final Object COMPOSING = new ComposingText();
-
private final TextView mTextView;
- private Object[] mDefaultComposingSpans;
-
public EditableInputConnection(TextView textview) {
- super(textview);
+ super(textview, false);
mTextView = textview;
}
- public static final void removeComposingSpans(Spannable text) {
- text.removeSpan(COMPOSING);
- Object[] sps = text.getSpans(0, text.length(), Object.class);
- if (sps != null) {
- for (int i=sps.length-1; i>=0; i--) {
- Object o = sps[i];
- if ((text.getSpanFlags(o)&Spanned.SPAN_COMPOSING) != 0) {
- text.removeSpan(o);
- }
- }
- }
- }
-
- public static void setComposingSpans(Spannable text) {
- final Object[] sps = text.getSpans(0, text.length(), Object.class);
- if (sps != null) {
- for (int i=sps.length-1; i>=0; i--) {
- final Object o = sps[i];
- if (o == COMPOSING) {
- text.removeSpan(o);
- continue;
- }
- final int fl = text.getSpanFlags(o);
- if ((fl&(Spanned.SPAN_COMPOSING|Spanned.SPAN_POINT_MARK_MASK))
- != (Spanned.SPAN_COMPOSING|Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)) {
- text.setSpan(o, text.getSpanStart(o), text.getSpanEnd(o),
- (fl&Spanned.SPAN_POINT_MARK_MASK)
- | Spanned.SPAN_COMPOSING
- | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
+ public Editable getEditable() {
+ TextView tv = mTextView;
+ if (tv != null) {
+ return tv.getEditableText();
}
-
- text.setSpan(COMPOSING, 0, text.length(),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
- }
-
- public static int getComposingSpanStart(Spannable text) {
- return text.getSpanStart(COMPOSING);
+ return null;
}
- public static int getComposingSpanEnd(Spannable text) {
- return text.getSpanEnd(COMPOSING);
+ public boolean beginBatchEdit() {
+ mTextView.beginBatchEdit();
+ return true;
}
- public boolean setComposingText(CharSequence text, int newCursorPosition) {
- if (DEBUG) Log.v(TAG, "setComposingText " + text);
- replaceText(text, newCursorPosition, true);
+ public boolean endBatchEdit() {
+ mTextView.endBatchEdit();
return true;
}
-
- public boolean finishComposingText() {
- if (DEBUG) Log.v(TAG, "finishComposingText");
+
+ public boolean clearMetaKeyStates(int states) {
final Editable content = getEditable();
- if (content != null) {
- removeComposingSpans(content);
- }
+ if (content == null) return false;
+ KeyListener kl = mTextView.getKeyListener();
+ if (kl != null) kl.clearMetaKeyState(mTextView, content, states);
return true;
}
- public boolean commitText(CharSequence text, int newCursorPosition) {
- if (DEBUG) Log.v(TAG, "commitText " + text);
- replaceText(text, newCursorPosition, false);
- return true;
- }
-
public boolean commitCompletion(CompletionInfo text) {
if (DEBUG) Log.v(TAG, "commitCompletion " + text);
+ mTextView.beginBatchEdit();
mTextView.onCommitCompletion(text);
+ mTextView.endBatchEdit();
return true;
}
- public CharSequence getTextBeforeCursor(int length) {
- final Editable content = getEditable();
- if (content == null) return null;
-
- int a = Selection.getSelectionStart(content);
- int b = Selection.getSelectionEnd(content);
-
- if (a > b) {
- int tmp = a;
- a = b;
- b = tmp;
- }
-
- if (length > a) {
- length = a;
- }
-
- return content.subSequence(a - length, a);
- }
-
- public CharSequence getTextAfterCursor(int length) {
- final Editable content = getEditable();
- if (content == null) return null;
-
- int a = Selection.getSelectionStart(content);
- int b = Selection.getSelectionEnd(content);
-
- if (a > b) {
- int tmp = a;
- a = b;
- b = tmp;
- }
-
- if (b + length > content.length()) {
- length = content.length() - b;
- }
-
- return content.subSequence(b, b + length);
- }
-
- public int getCursorCapsMode(int reqModes) {
- final Editable content = getEditable();
- if (content == null) return 0;
-
- int a = Selection.getSelectionStart(content);
- int b = Selection.getSelectionEnd(content);
-
- if (a > b) {
- int tmp = a;
- a = b;
- b = tmp;
- }
-
- return TextUtils.getCapsMode(content, a, reqModes);
+ public boolean performContextMenuAction(int id) {
+ if (DEBUG) Log.v(TAG, "performContextMenuAction " + id);
+ mTextView.beginBatchEdit();
+ mTextView.onTextContextMenuItem(id);
+ mTextView.endBatchEdit();
+ return true;
}
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
if (mTextView != null) {
ExtractedText et = new ExtractedText();
if (mTextView.extractText(request, et)) {
- if ((flags&EXTRACTED_TEXT_MONITOR) != 0) {
+ if ((flags&GET_EXTRACTED_TEXT_MONITOR) != 0) {
mTextView.setExtracting(request);
}
return et;
@@ -193,173 +92,8 @@ public class EditableInputConnection extends BaseInputConnection {
return null;
}
- public boolean deleteSurroundingText(int leftLength, int rightLength) {
- if (DEBUG) Log.v(TAG, "deleteSurroundingText " + leftLength
- + " / " + rightLength);
- final Editable content = getEditable();
- if (content == null) return false;
-
- int a = Selection.getSelectionStart(content);
- int b = Selection.getSelectionEnd(content);
-
- if (a > b) {
- int tmp = a;
- a = b;
- b = tmp;
- }
-
- // ignore the composing text.
- int ca = content.getSpanStart(COMPOSING);
- int cb = content.getSpanEnd(COMPOSING);
- if (cb < ca) {
- int tmp = ca;
- ca = cb;
- cb = tmp;
- }
- if (ca != -1 && cb != -1) {
- if (ca < a) a = ca;
- if (cb > b) b = cb;
- }
-
- int deleted = 0;
-
- if (leftLength > 0) {
- int start = a - leftLength;
- if (start < 0) start = 0;
- content.delete(start, a);
- deleted = a - start;
- }
-
- if (rightLength > 0) {
- b = b - deleted;
-
- int end = b + rightLength;
- if (end > content.length()) end = content.length();
-
- content.delete(b, end);
- }
-
- return true;
- }
-
- public boolean beginBatchEdit() {
- if (mTextView == null) return false;
- mTextView.onBeginBatchEdit();
- return true;
- }
-
- public boolean endBatchEdit() {
- if (mTextView == null) return false;
- mTextView.onEndBatchEdit();
- return true;
- }
-
- public boolean clearMetaKeyStates(int states) {
- final Editable content = getEditable();
- if (content == null) return false;
- KeyListener kl = mTextView.getKeyListener();
- if (kl != null) kl.clearMetaKeyState(mTextView, content, states);
- return true;
- }
-
public boolean performPrivateCommand(String action, Bundle data) {
- if (mTextView == null) return false;
mTextView.onPrivateIMECommand(action, data);
return true;
}
-
- private Editable getEditable() {
- TextView tv = mTextView;
- if (tv != null) {
- return tv.getEditableText();
- }
- return null;
- }
-
- private void replaceText(CharSequence text, int newCursorPosition,
- boolean composing) {
- final Editable content = getEditable();
-
- // delete composing text set previously.
- int a = content.getSpanStart(COMPOSING);
- int b = content.getSpanEnd(COMPOSING);
-
- if (DEBUG) Log.v(TAG, "Composing span: " + a + " to " + b);
-
- if (b < a) {
- int tmp = a;
- a = b;
- b = tmp;
- }
-
- if (a != -1 && b != -1) {
- removeComposingSpans(content);
- } else {
- a = Selection.getSelectionStart(content);
- b = Selection.getSelectionEnd(content);
- if (a >=0 && b>= 0 && a != b) {
- if (b < a) {
- int tmp = a;
- a = b;
- b = tmp;
- }
- }
- }
-
- if (composing) {
- Spannable sp = null;
- if (!(text instanceof Spannable)) {
- sp = new SpannableStringBuilder(text);
- text = sp;
- if (mDefaultComposingSpans == null) {
- TypedArray ta = mTextView.getContext().getTheme()
- .obtainStyledAttributes(new int[] {
- com.android.internal.R.attr.candidatesTextStyleSpans
- });
- CharSequence style = ta.getText(0);
- ta.recycle();
- if (style != null && style instanceof Spanned) {
- mDefaultComposingSpans = ((Spanned)style).getSpans(
- 0, style.length(), Object.class);
- }
- }
- if (mDefaultComposingSpans != null) {
- for (int i = 0; i < mDefaultComposingSpans.length; ++i) {
- sp.setSpan(mDefaultComposingSpans[i], 0, sp.length(),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- } else {
- sp = (Spannable)text;
- }
- setComposingSpans(sp);
- }
-
- // Adjust newCursorPosition to be relative the start of the text.
- newCursorPosition += a;
-
- if (DEBUG) Log.v(TAG, "Replacing from " + a + " to " + b + " with \""
- + text + "\", composing=" + composing
- + ", type=" + text.getClass().getCanonicalName());
-
- if (DEBUG) {
- LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG);
- lp.println("Current text:");
- TextUtils.dumpSpans(content, lp, " ");
- lp.println("Composing text:");
- TextUtils.dumpSpans(text, lp, " ");
- }
-
- content.replace(a, b, text);
- if (newCursorPosition < 0) newCursorPosition = 0;
- if (newCursorPosition > content.length())
- newCursorPosition = content.length();
- Selection.setSelection(content, newCursorPosition);
-
- if (DEBUG) {
- LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG);
- lp.println("Final text:");
- TextUtils.dumpSpans(content, lp, " ");
- }
- }
}
diff --git a/core/java/com/android/internal/widget/SlidingDrawer.java b/core/java/com/android/internal/widget/SlidingDrawer.java
deleted file mode 100644
index a4045d5..0000000
--- a/core/java/com/android/internal/widget/SlidingDrawer.java
+++ /dev/null
@@ -1,924 +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.view.ViewGroup;
-import android.view.View;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.SoundEffectConstants;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.Bitmap;
-import android.os.SystemClock;
-import android.os.Handler;
-import android.os.Message;
-import com.android.internal.R;
-
-/**
- * SlidingDrawer hides content out of the screen and allows the user to drag a handle
- * to bring the content on screen. SlidingDrawer can be used vertically or horizontally.
- *
- * A special widget composed of two children views: the handle, that the users drags,
- * and the content, attached to the handle and dragged with it.
- *
- * SlidingDrawer should be used as an overlay inside layouts. This means SlidingDrawer
- * should only be used inside of a FrameLayout or a RelativeLayout for instance. The
- * size of the SlidingDrawer defines how much space the content will occupy once slid
- * out so SlidingDrawer should usually use fill_parent for both its dimensions.
- *
- * Inside an XML layout, SlidingDrawer must define the id of the handle and of the
- * content:
- *
- * <pre class="prettyprint">
- * &lt;com.android.internal.widget.SlidingDrawer
- * android:id="@+id/drawer"
- * android:layout_width="fill_parent"
- * android:layout_height="fill_parent"
- *
- * android:handle="@+id/handle"
- * android:content="@+id/content"&gt;
- *
- * &lt;ImageView
- * android:id="@id/handle"
- * android:layout_width="88dip"
- * android:layout_height="44dip" /&gt;
- *
- * &lt;GridView
- * android:id="@id/content"
- * android:layout_width="fill_parent"
- * android:layout_height="fill_parent" /&gt;
- *
- * &lt;/com.android.internal.widget.SlidingDrawer&gt;
- * </pre>
- *
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_content
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_handle
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_topOffset
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_bottomOffset
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_orientation
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_allowSingleTap
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_animateOnClick
- */
-public class SlidingDrawer extends ViewGroup {
- public static final int ORIENTATION_HORIZONTAL = 0;
- public static final int ORIENTATION_VERTICAL = 1;
-
- private static final int TAP_THRESHOLD = 6;
- private static final float MAXIMUM_TAP_VELOCITY = 100.0f;
- private static final float MAXIMUM_MINOR_VELOCITY = 150.0f;
- private static final float MAXIMUM_MAJOR_VELOCITY = 200.0f;
- private static final float MAXIMUM_ACCELERATION = 2000.0f;
- private static final int VELOCITY_UNITS = 1000;
- private static final int MSG_ANIMATE = 1000;
- private static final int ANIMATION_FRAME_DURATION = 1000 / 60;
-
- private static final int EXPANDED_FULL_OPEN = -10001;
- private static final int COLLAPSED_FULL_CLOSED = -10002;
-
- private final int mHandleId;
- private final int mContentId;
-
- private View mHandle;
- private View mContent;
-
- private final Rect mFrame = new Rect();
- private final Rect mInvalidate = new Rect();
- private boolean mTracking;
- private boolean mLocked;
-
- private VelocityTracker mVelocityTracker;
-
- private boolean mVertical;
- private boolean mExpanded;
- private int mBottomOffset;
- private int mTopOffset;
- private int mHandleHeight;
- private int mHandleWidth;
-
- private OnDrawerOpenListener mOnDrawerOpenListener;
- private OnDrawerCloseListener mOnDrawerCloseListener;
- private OnDrawerScrollListener mOnDrawerScrollListener;
-
- private final Handler mHandler = new SlidingHandler();
- private float mAnimatedAcceleration;
- private float mAnimatedVelocity;
- private float mAnimationPosition;
- private long mAnimationLastTime;
- private long mCurrentAnimationTime;
- private int mTouchDelta;
- private boolean mAnimating;
- private boolean mAllowSingleTap;
- private boolean mAnimateOnClick;
-
- /**
- * Callback invoked when the drawer is opened.
- */
- public static interface OnDrawerOpenListener {
- /**
- * Invoked when the drawer becomes fully open.
- */
- public void onDrawerOpened();
- }
-
- /**
- * Callback invoked when the drawer is closed.
- */
- public static interface OnDrawerCloseListener {
- /**
- * Invoked when the drawer becomes fully closed.
- */
- public void onDrawerClosed();
- }
-
- /**
- * Callback invoked when the drawer is scrolled.
- */
- public static interface OnDrawerScrollListener {
- /**
- * Invoked when the user starts dragging/flinging the drawer's handle.
- */
- public void onScrollStarted();
-
- /**
- * Invoked when the user stops dragging/flinging the drawer's handle.
- */
- public void onScrollEnded();
- }
-
- /**
- * Creates a new SlidingDrawer from a specified set of attributes defined in XML.
- *
- * @param context The application's environment.
- * @param attrs The attributes defined in XML.
- */
- public SlidingDrawer(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- /**
- * Creates a new SlidingDrawer from a specified set of attributes defined in XML.
- *
- * @param context The application's environment.
- * @param attrs The attributes defined in XML.
- * @param defStyle The style to apply to this widget.
- */
- public SlidingDrawer(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingDrawer, defStyle, 0);
-
- int orientation = a.getInt(R.styleable.SlidingDrawer_orientation, ORIENTATION_VERTICAL);
- mVertical = orientation == ORIENTATION_VERTICAL;
- mBottomOffset = (int) a.getDimension(R.styleable.SlidingDrawer_bottomOffset, 0.0f);
- mTopOffset = (int) a.getDimension(R.styleable.SlidingDrawer_topOffset, 0.0f);
- mAllowSingleTap = a.getBoolean(R.styleable.SlidingDrawer_allowSingleTap, true);
- mAnimateOnClick = a.getBoolean(R.styleable.SlidingDrawer_animateOnClick, true);
-
- int handleId = a.getResourceId(R.styleable.SlidingDrawer_handle, 0);
- if (handleId == 0) {
- throw new IllegalArgumentException("The handle attribute is required and must refer "
- + "to a valid child.");
- }
-
- int contentId = a.getResourceId(R.styleable.SlidingDrawer_content, 0);
- if (contentId == 0) {
- throw new IllegalArgumentException("The handle attribute is required and must refer "
- + "to a valid child.");
- }
-
- mHandleId = handleId;
- mContentId = contentId;
-
- a.recycle();
-
- setAlwaysDrawnWithCacheEnabled(false);
- }
-
- @Override
- protected void onFinishInflate() {
- mHandle = findViewById(mHandleId);
- if (mHandle == null) {
- throw new IllegalArgumentException("The handle attribute is must refer to an"
- + " existing child.");
- }
- mHandle.setOnClickListener(new DrawerToggler());
-
- mContent = findViewById(mContentId);
- if (mContent == null) {
- throw new IllegalArgumentException("The content attribute is must refer to an"
- + " existing child.");
- }
- mContent.setVisibility(View.GONE);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
-
- int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
-
- if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
- throw new RuntimeException("SlidingDrawer cannot have UNSPECIFIED dimensions");
- }
-
- final View handle = mHandle;
- measureChild(handle, widthMeasureSpec, heightMeasureSpec);
-
- if (mVertical) {
- int height = heightSpecSize - handle.getMeasuredHeight() - mTopOffset;
- mContent.measure(MeasureSpec.makeMeasureSpec(widthSpecSize, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
- } else {
- int width = widthSpecSize - handle.getMeasuredWidth() - mTopOffset;
- mContent.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(heightSpecSize, MeasureSpec.EXACTLY));
- }
-
- setMeasuredDimension(widthSpecSize, heightSpecSize);
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- final long drawingTime = getDrawingTime();
- final View handle = mHandle;
- final boolean isVertical = mVertical;
-
- drawChild(canvas, handle, drawingTime);
-
- if (mTracking || mAnimating) {
- final Bitmap cache = mContent.getDrawingCache();
- if (cache != null) {
- if (isVertical) {
- canvas.drawBitmap(cache, 0, handle.getBottom(), null);
- } else {
- canvas.drawBitmap(cache, handle.getRight(), 0, null);
- }
- } else {
- canvas.save();
- canvas.translate(isVertical ? 0 : handle.getLeft() - mTopOffset,
- isVertical ? handle.getTop() - mTopOffset : 0);
- drawChild(canvas, mContent, drawingTime);
- canvas.restore();
- }
- } else if (mExpanded) {
- drawChild(canvas, mContent, drawingTime);
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- if (mTracking) {
- return;
- }
-
- final int width = r - l;
- final int height = b - t;
-
- final View handle = mHandle;
-
- int childWidth = handle.getMeasuredWidth();
- int childHeight = handle.getMeasuredHeight();
-
- int childLeft;
- int childTop;
-
- final View content = mContent;
-
- if (mVertical) {
- childLeft = (width - childWidth) / 2;
- childTop = mExpanded ? mTopOffset : height - childHeight + mBottomOffset;
-
- content.layout(0, mTopOffset + childHeight, content.getMeasuredWidth(),
- mTopOffset + childHeight + content.getMeasuredHeight());
- } else {
- childLeft = mExpanded ? mTopOffset : width - childWidth + mBottomOffset;
- childTop = (height - childHeight) / 2;
-
- content.layout(mTopOffset + childWidth, 0,
- mTopOffset + childWidth + content.getMeasuredWidth(),
- content.getMeasuredHeight());
- }
-
- handle.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
- mHandleHeight = handle.getHeight();
- mHandleWidth = handle.getWidth();
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mLocked) {
- return false;
- }
-
- final int action = event.getAction();
-
- float x = event.getX();
- float y = event.getY();
-
- final Rect frame = mFrame;
- final View handle = mHandle;
-
- handle.getHitRect(frame);
- if (!mTracking && !frame.contains((int) x, (int) y)) {
- return false;
- }
-
- if (action == MotionEvent.ACTION_DOWN) {
- if (mOnDrawerScrollListener != null) {
- mOnDrawerScrollListener.onScrollStarted();
- }
- mTracking = true;
-
- handle.setPressed(true);
- // Must be called before prepareTracking()
- prepareContent();
-
- if (mVertical) {
- final int top = mHandle.getTop();
- mTouchDelta = (int) y - top;
- prepareTracking(top);
- } else {
- final int left = mHandle.getLeft();
- mTouchDelta = (int) x - left;
- prepareTracking(left);
- }
- mVelocityTracker.addMovement(event);
- }
-
- return true;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mLocked) {
- return true;
- }
-
- if (mTracking) {
- mVelocityTracker.addMovement(event);
- final int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_MOVE:
- moveHandle((int) (mVertical ? event.getY() : event.getX()) - mTouchDelta);
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL: {
- final VelocityTracker velocityTracker = mVelocityTracker;
- velocityTracker.computeCurrentVelocity(VELOCITY_UNITS);
-
- float yVelocity = velocityTracker.getYVelocity();
- float xVelocity = velocityTracker.getXVelocity();
- boolean negative;
-
- final boolean vertical = mVertical;
- if (vertical) {
- negative = yVelocity < 0;
- if (xVelocity < 0) {
- xVelocity = -xVelocity;
- }
- if (xVelocity > MAXIMUM_MINOR_VELOCITY) {
- xVelocity = MAXIMUM_MINOR_VELOCITY;
- }
- } else {
- negative = xVelocity < 0;
- if (yVelocity < 0) {
- yVelocity = -yVelocity;
- }
- if (yVelocity > MAXIMUM_MINOR_VELOCITY) {
- yVelocity = MAXIMUM_MINOR_VELOCITY;
- }
- }
-
- float velocity = (float) Math.hypot(xVelocity, yVelocity);
- if (negative) {
- velocity = -velocity;
- }
-
- final int top = mHandle.getTop();
- final int left = mHandle.getLeft();
-
- if (Math.abs(velocity) < MAXIMUM_TAP_VELOCITY) {
- if (vertical ? (mExpanded && top < TAP_THRESHOLD + mTopOffset) ||
- (!mExpanded && top > mBottomOffset + mBottom - mTop -
- mHandleHeight - TAP_THRESHOLD) :
- (mExpanded && left < TAP_THRESHOLD + mTopOffset) ||
- (!mExpanded && left > mBottomOffset + mRight - mLeft -
- mHandleWidth - TAP_THRESHOLD)) {
-
- if (mAllowSingleTap) {
- playSoundEffect(SoundEffectConstants.CLICK);
-
- if (mExpanded) {
- animateClose(vertical ? top : left);
- } else {
- animateOpen(vertical ? top : left);
- }
- }
-
- } else {
- performFling(vertical ? top : left, velocity, false);
- }
- } else {
- performFling(vertical ? top : left, velocity, false);
- }
- }
- break;
- }
- }
-
- return mTracking || mAnimating || super.onTouchEvent(event);
- }
-
- private void animateClose(int position) {
- prepareTracking(position);
- performFling(position, 2000.0f, true);
- }
-
- private void animateOpen(int position) {
- prepareTracking(position);
- performFling(position, -2000.0f, true);
- }
-
- private void performFling(int position, float velocity, boolean always) {
- mAnimationPosition = position;
- mAnimatedVelocity = velocity;
-
- if (mExpanded) {
- if (always || (velocity > MAXIMUM_MAJOR_VELOCITY ||
- (position > mTopOffset + (mVertical ? mHandleHeight : mHandleWidth) &&
- velocity > -MAXIMUM_MAJOR_VELOCITY))) {
- // We are expanded, but they didn't move sufficiently to cause
- // us to retract. Animate back to the expanded position.
- mAnimatedAcceleration = MAXIMUM_ACCELERATION;
- if (velocity < 0) {
- mAnimatedVelocity = 0;
- }
- } else {
- // We are expanded and are now going to animate away.
- mAnimatedAcceleration = -MAXIMUM_ACCELERATION;
- if (velocity > 0) {
- mAnimatedVelocity = 0;
- }
- }
- } else {
- if (!always && (velocity > MAXIMUM_MAJOR_VELOCITY ||
- (position > (mVertical ? getHeight() : getWidth()) / 2 &&
- velocity > -MAXIMUM_MAJOR_VELOCITY))) {
- // We are collapsed, and they moved enough to allow us to expand.
- mAnimatedAcceleration = MAXIMUM_ACCELERATION;
- if (velocity < 0) {
- mAnimatedVelocity = 0;
- }
- } else {
- // We are collapsed, but they didn't move sufficiently to cause
- // us to retract. Animate back to the collapsed position.
- mAnimatedAcceleration = -MAXIMUM_ACCELERATION;
- if (velocity > 0) {
- mAnimatedVelocity = 0;
- }
- }
- }
-
- long now = SystemClock.uptimeMillis();
- mAnimationLastTime = now;
- mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
- mAnimating = true;
- mHandler.removeMessages(MSG_ANIMATE);
- mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurrentAnimationTime);
- stopTracking();
- }
-
- private void prepareTracking(int position) {
- mTracking = true;
- mVelocityTracker = VelocityTracker.obtain();
- boolean opening = !mExpanded;
- if (opening) {
- mAnimatedAcceleration = MAXIMUM_ACCELERATION;
- mAnimatedVelocity = 200;
- mAnimationPosition = mBottomOffset +
- (mVertical ? getHeight() - mHandleHeight : getWidth() - mHandleWidth);
- moveHandle((int) mAnimationPosition);
- mAnimating = true;
- mHandler.removeMessages(MSG_ANIMATE);
- long now = SystemClock.uptimeMillis();
- mAnimationLastTime = now;
- mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
- mAnimating = true;
- } else {
- if (mAnimating) {
- mAnimating = false;
- mHandler.removeMessages(MSG_ANIMATE);
- }
- moveHandle(position);
- }
- }
-
- private void moveHandle(int position) {
- final View handle = mHandle;
-
- if (mVertical) {
- if (position == EXPANDED_FULL_OPEN) {
- handle.offsetTopAndBottom(mTopOffset - handle.getTop());
- invalidate();
- } else if (position == COLLAPSED_FULL_CLOSED) {
- handle.offsetTopAndBottom(mBottomOffset + mBottom - mTop -
- mHandleHeight - handle.getTop());
- invalidate();
- } else {
- final int top = handle.getTop();
- int deltaY = position - top;
- if (position < mTopOffset) {
- deltaY = mTopOffset - top;
- } else if (deltaY > mBottomOffset + mBottom - mTop - mHandleHeight - top) {
- deltaY = mBottomOffset + mBottom - mTop - mHandleHeight - top;
- }
- handle.offsetTopAndBottom(deltaY);
-
- final Rect frame = mFrame;
- final Rect region = mInvalidate;
-
- handle.getHitRect(frame);
- region.set(frame);
-
- region.union(frame.left, frame.top - deltaY, frame.right, frame.bottom - deltaY);
- region.union(0, frame.bottom - deltaY, getWidth(),
- frame.bottom - deltaY + mContent.getHeight());
-
- invalidate(region);
- }
- } else {
- if (position == EXPANDED_FULL_OPEN) {
- handle.offsetLeftAndRight(mTopOffset - handle.getLeft());
- invalidate();
- } else if (position == COLLAPSED_FULL_CLOSED) {
- handle.offsetLeftAndRight(mBottomOffset + mRight - mLeft -
- mHandleWidth - handle.getLeft());
- invalidate();
- } else {
- final int left = handle.getLeft();
- int deltaX = position - left;
- if (position < mTopOffset) {
- deltaX = mTopOffset - left;
- } else if (deltaX > mBottomOffset + mRight - mLeft - mHandleWidth - left) {
- deltaX = mBottomOffset + mRight - mLeft - mHandleWidth - left;
- }
- handle.offsetLeftAndRight(deltaX);
-
- final Rect frame = mFrame;
- final Rect region = mInvalidate;
-
- handle.getHitRect(frame);
- region.set(frame);
-
- region.union(frame.left - deltaX, frame.top, frame.right - deltaX, frame.bottom);
- region.union(frame.right - deltaX, 0,
- frame.right - deltaX + mContent.getWidth(), getHeight());
-
- invalidate(region);
- }
- }
- }
-
- private void prepareContent() {
- if (mAnimating) {
- return;
- }
-
- // Something changed in the content, we need to honor the layout request
- // before creating the cached bitmap
- final View content = mContent;
- if (content.isLayoutRequested()) {
- if (mVertical) {
- final int childHeight = mHandleHeight;
- int height = mBottom - mTop - childHeight - mTopOffset;
- content.measure(MeasureSpec.makeMeasureSpec(mRight - mLeft, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
- content.layout(0, mTopOffset + childHeight, content.getMeasuredWidth(),
- mTopOffset + childHeight + content.getMeasuredHeight());
- } else {
- final int childWidth = mHandle.getWidth();
- int width = mRight - mLeft - childWidth - mTopOffset;
- content.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(mBottom - mTop, MeasureSpec.EXACTLY));
- content.layout(childWidth + mTopOffset, 0,
- mTopOffset + childWidth + content.getMeasuredWidth(),
- content.getMeasuredHeight());
- }
- }
- // Try only once... we should really loop but it's not a big deal
- // if the draw was cancelled, it will only be temporary anyway
- content.getViewTreeObserver().dispatchOnPreDraw();
- content.buildDrawingCache();
-
- content.setVisibility(View.GONE);
- }
-
- private void stopTracking() {
- mHandle.setPressed(false);
- mTracking = false;
-
- if (mOnDrawerScrollListener != null) {
- mOnDrawerScrollListener.onScrollEnded();
- }
-
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- }
-
- private void doAnimation() {
- if (mAnimating) {
- incrementAnimation();
- if (mAnimationPosition >= mBottomOffset + (mVertical ? getHeight() : getWidth()) - 1) {
- mAnimating = false;
- closeDrawer();
- } else if (mAnimationPosition < mTopOffset) {
- mAnimating = false;
- openDrawer();
- } else {
- moveHandle((int) mAnimationPosition);
- mCurrentAnimationTime += ANIMATION_FRAME_DURATION;
- mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE),
- mCurrentAnimationTime);
- }
- }
- }
-
- private void incrementAnimation() {
- long now = SystemClock.uptimeMillis();
- float t = (now - mAnimationLastTime) / 1000.0f; // ms -> s
- final float position = mAnimationPosition;
- final float v = mAnimatedVelocity; // px/s
- final float a = mAnimatedAcceleration; // px/s/s
- mAnimationPosition = position + (v * t) + (0.5f * a * t * t); // px
- mAnimatedVelocity = v + (a * t); // px/s
- mAnimationLastTime = now; // ms
- }
-
- /**
- * Toggles the drawer open and close. Takes effect immediately.
- *
- * @see #open()
- * @see #close()
- * @see #animateClose()
- * @see #animateOpen()
- * @see #animateToggle()
- */
- public void toggle() {
- if (!mExpanded) {
- openDrawer();
- } else {
- closeDrawer();
- }
- invalidate();
- requestLayout();
- }
-
- /**
- * Toggles the drawer open and close with an animation.
- *
- * @see #open()
- * @see #close()
- * @see #animateClose()
- * @see #animateOpen()
- * @see #toggle()
- */
- public void animateToggle() {
- if (!mExpanded) {
- animateOpen();
- } else {
- animateClose();
- }
- }
-
- /**
- * Opens the drawer immediately.
- *
- * @see #toggle()
- * @see #close()
- * @see #animateOpen()
- */
- public void open() {
- openDrawer();
- invalidate();
- requestLayout();
- }
-
- /**
- * Closes the drawer immediately.
- *
- * @see #toggle()
- * @see #open()
- * @see #animateClose()
- */
- public void close() {
- closeDrawer();
- invalidate();
- requestLayout();
- }
-
- /**
- * Closes the drawer with an animation.
- *
- * @see #close()
- * @see #open()
- * @see #animateOpen()
- * @see #animateToggle()
- * @see #toggle()
- */
- public void animateClose() {
- final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;
- if (scrollListener != null) {
- scrollListener.onScrollStarted();
- }
- prepareContent();
- animateClose(mVertical ? mHandle.getTop() : mHandle.getLeft());
- if (scrollListener != null) {
- scrollListener.onScrollEnded();
- }
- }
-
- /**
- * Opens the drawer with an animation.
- *
- * @see #close()
- * @see #open()
- * @see #animateClose()
- * @see #animateToggle()
- * @see #toggle()
- */
- public void animateOpen() {
- final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;
- if (scrollListener != null) {
- scrollListener.onScrollStarted();
- }
- prepareContent();
- animateOpen(mVertical ? mHandle.getTop() : mHandle.getLeft());
- if (scrollListener != null) {
- scrollListener.onScrollEnded();
- }
- }
-
- private void closeDrawer() {
- moveHandle(COLLAPSED_FULL_CLOSED);
- mContent.setVisibility(View.GONE);
-
- if (!mExpanded) {
- return;
- }
-
- mExpanded = false;
- if (mOnDrawerCloseListener != null) {
- mOnDrawerCloseListener.onDrawerClosed();
- }
- }
-
- private void openDrawer() {
- moveHandle(EXPANDED_FULL_OPEN);
- mContent.setVisibility(View.VISIBLE);
- // TODO: Should we uncomment to preserve memory, but increase memory churn?
- // mContent.destroyDrawingCache();
-
- if (mExpanded) {
- return;
- }
-
- mExpanded = true;
- if (mOnDrawerOpenListener != null) {
- mOnDrawerOpenListener.onDrawerOpened();
- }
- }
-
- /**
- * Sets the listener that receives a notification when the drawer becomes open.
- *
- * @param onDrawerOpenListener The listener to be notified when the drawer is opened.
- */
- public void setOnDrawerOpenListener(OnDrawerOpenListener onDrawerOpenListener) {
- mOnDrawerOpenListener = onDrawerOpenListener;
- }
-
- /**
- * Sets the listener that receives a notification when the drawer becomes close.
- *
- * @param onDrawerCloseListener The listener to be notified when the drawer is closed.
- */
- public void setOnDrawerCloseListener(OnDrawerCloseListener onDrawerCloseListener) {
- mOnDrawerCloseListener = onDrawerCloseListener;
- }
-
- /**
- * Sets the listener that receives a notification when the drawer starts or ends
- * a scroll. A fling is considered as a scroll. A fling will also trigger a
- * drawer opened or drawer closed event.
- *
- * @param onDrawerScrollListener The listener to be notified when scrolling
- * starts or stops.
- */
- public void setOnDrawerScrollListener(OnDrawerScrollListener onDrawerScrollListener) {
- mOnDrawerScrollListener = onDrawerScrollListener;
- }
-
- /**
- * Returns the handle of the drawer.
- *
- * @return The View reprenseting the handle of the drawer, identified by
- * the "handle" id in XML.
- */
- public View getHandle() {
- return mHandle;
- }
-
- /**
- * Returns the content of the drawer.
- *
- * @return The View reprenseting the content of the drawer, identified by
- * the "content" id in XML.
- */
- public View getContent() {
- return mContent;
- }
-
- /**
- * Unlocks the SlidingDrawer so that touch events are processed.
- *
- * @see #lock()
- */
- public void unlock() {
- mLocked = false;
- }
-
- /**
- * Locks the SlidingDrawer so that touch events are ignores.
- *
- * @see #unlock()
- */
- public void lock() {
- mLocked = true;
- }
-
- /**
- * Indicates whether the drawer is currently fully opened.
- *
- * @return True if the drawer is opened, false otherwise.
- */
- public boolean isOpened() {
- return mExpanded;
- }
-
- /**
- * Indicates whether the drawer is scrolling or flinging.
- *
- * @return True if the drawer is scroller or flinging, false otherwise.
- */
- public boolean isMoving() {
- return mTracking || mAnimating;
- }
-
- private class DrawerToggler implements OnClickListener {
- public void onClick(View v) {
- if (mLocked) {
- return;
- }
- // mAllowSingleTap isn't relevant here; you're *always*
- // allowed to open/close the drawer by clicking with the
- // trackball.
-
- if (mAnimateOnClick) {
- animateToggle();
- } else {
- toggle();
- }
- }
- }
-
- private class SlidingHandler extends Handler {
- public void handleMessage(Message m) {
- switch (m.what) {
- case MSG_ANIMATE:
- doAnimation();
- break;
- }
- }
- }
-}