Merge "Fixing bug 2455152 - Enabled accessibility services are disabled upon restarting accessibility"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ad4596e..a7066e0 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -39,6 +39,7 @@
<uses-permission android:name="android.permission.BATTERY_STATS"/>
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.MOVE_PACKAGE" />
<application android:label="@string/settings_label"
android:icon="@drawable/ic_launcher_settings"
diff --git a/res/layout/power_usage_action_item.xml b/res/layout/power_usage_action_item.xml
index a53c551..e4d8b5a 100644
--- a/res/layout/power_usage_action_item.xml
+++ b/res/layout/power_usage_action_item.xml
@@ -28,6 +28,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
+ android:paddingBottom="4dip"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium"/>
diff --git a/res/layout/power_usage_details.xml b/res/layout/power_usage_details.xml
index 18781a9..23be53f 100644
--- a/res/layout/power_usage_details.xml
+++ b/res/layout/power_usage_details.xml
@@ -87,6 +87,17 @@
</RelativeLayout>
</LinearLayout>
+ <!-- Force stop and report buttons -->
+ <LinearLayout
+ android:id="@+id/two_buttons_panel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="6dip"
+ android:orientation="vertical">
+ <include
+ layout="@layout/two_buttons_panel"/>
+ </LinearLayout>
+
<TextView
style="?android:attr/listSeparatorTextViewStyle"
android:text="@string/details_subtitle" />
diff --git a/res/layout/running_services.xml b/res/layout/running_services.xml
index 2f464a5..5c0da6f 100644
--- a/res/layout/running_services.xml
+++ b/res/layout/running_services.xml
@@ -35,20 +35,20 @@
android:text="@string/no_running_services"
android:textAppearance="?android:attr/textAppearanceLarge" />
</FrameLayout>
- <LinearLayout
+ <view class="com.android.settings.RunningServices$LinearColorBar"
+ android:id="@+id/color_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:background="?android:attr/colorForeground"
android:padding="4dp">
- <TextView android:id="@+id/backgroundText"
+ <TextView android:id="@+id/foregroundText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceSmallInverse"
android:color="?android:attr/textColorPrimaryInverse"
android:singleLine="true" />
- <TextView android:id="@+id/foregroundText"
+ <TextView android:id="@+id/backgroundText"
android:layout_gravity="center_vertical|right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -56,5 +56,5 @@
android:textAppearance="?android:attr/textAppearanceSmallInverse"
android:color="?android:attr/textColorPrimaryInverse"
android:singleLine="true" />
- </LinearLayout>
+ </view>
</LinearLayout>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index ae0fba8..ff68cc7 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -354,4 +354,18 @@
<item>3</item>
</string-array>
+ <!-- Apps on SD instalaltion location options in ApplicationSettings -->
+ <string-array name="app_install_location_entries">
+ <item>Internal device storage</item>
+ <item>Removable SD card</item>
+ <item>Let the system decide</item>
+ </string-array>
+
+ <!-- Do not translate. -->
+ <string-array name="app_install_location_values" translatable="false">
+ <item>device</item>
+ <item>sdcard</item>
+ <item>auto</item>
+ </string-array>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3afe481..bc19df5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1117,7 +1117,7 @@
<string name="system_update_settings_list_item_summary">""</string>
<!-- About phone screen, status item label -->
- <string name="firmware_version">Firmware version</string>
+ <string name="firmware_version">Android version</string>
<!-- About phone screen, status item label-->
<string name="model_number">Model number</string>
<!-- About phone screen, setting option name-->
@@ -1628,9 +1628,15 @@
<!-- Manage applications, text for Move button to move app to sdcard -->
<string name="move_app_to_sdcard">Move to sdcard</string>
<!-- Manage applications, title for dialog when killing persistent apps-->
+ <!-- Manage applications, text for Move button when move is in progress -->
+ <string name="moving">Moving</string>
<string name="force_stop_dlg_title">Force Stop</string>
<!-- Manage applications, text for dialog when killing persistent apps-->
<string name="force_stop_dlg_text">This application will be restarted right way. Are you sure you want to force stop?</string>
+ <!-- Manage applications, application installation location title -->
+ <string name="app_install_location_title">Preferred install location</string>
+ <!-- Manage applications. application installation location summary -->
+ <string name="app_install_location_summary">Change the preferred installation location for new applications.</string>
<!-- Services settings screen, setting option name for the user to go to the screen to view running services -->
<string name="runningservices_settings_title">Running services</string>
diff --git a/res/xml/application_settings.xml b/res/xml/application_settings.xml
index b5418e8..4df21da 100644
--- a/res/xml/application_settings.xml
+++ b/res/xml/application_settings.xml
@@ -25,7 +25,15 @@
android:summaryOff="@string/install_unknown_applications"
android:summaryOn="@string/install_unknown_applications"
android:persistent="false" />
-
+
+ <ListPreference
+ android:key="app_install_location"
+ android:title="@string/app_install_location_title"
+ android:summary="@string/app_install_location_summary"
+ android:persistent="false"
+ android:entries="@array/app_install_location_entries"
+ android:entryValues="@array/app_install_location_values"/>
+
<PreferenceScreen
android:key="quick_launch"
android:title="@string/quick_launch_title"
diff --git a/src/com/android/settings/ApplicationSettings.java b/src/com/android/settings/ApplicationSettings.java
index 6a8aa81..9b7a919 100644
--- a/src/com/android/settings/ApplicationSettings.java
+++ b/src/com/android/settings/ApplicationSettings.java
@@ -21,21 +21,35 @@
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
+import android.preference.Preference.OnPreferenceChangeListener;
import android.provider.Settings;
public class ApplicationSettings extends PreferenceActivity implements
DialogInterface.OnClickListener {
private static final String KEY_TOGGLE_INSTALL_APPLICATIONS = "toggle_install_applications";
+ private static final String KEY_APP_INSTALL_LOCATION = "app_install_location";
private static final String KEY_QUICK_LAUNCH = "quick_launch";
+ // App installation location. Default is ask the user.
+ private static final int APP_INSTALL_AUTO = 0;
+ private static final int APP_INSTALL_DEVICE = 1;
+ private static final int APP_INSTALL_SDCARD = 2;
+
+ private static final String APP_INSTALL_DEVICE_ID = "device";
+ private static final String APP_INSTALL_SDCARD_ID = "sdcard";
+ private static final String APP_INSTALL_AUTO_ID = "auto";
+
private CheckBoxPreference mToggleAppInstallation;
-
+
+ private ListPreference mInstallLocation;
+
private DialogInterface mWarnInstallApps;
-
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -45,6 +59,23 @@
mToggleAppInstallation = (CheckBoxPreference) findPreference(KEY_TOGGLE_INSTALL_APPLICATIONS);
mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());
+ mInstallLocation = (ListPreference) findPreference(KEY_APP_INSTALL_LOCATION);
+ // Is app default install location set?
+ boolean userSetInstLocation = (Settings.System.getInt(getContentResolver(),
+ Settings.System.SET_INSTALL_LOCATION, 0) != 0);
+ if (!userSetInstLocation) {
+ getPreferenceScreen().removePreference(mInstallLocation);
+ } else {
+ mInstallLocation.setValue(getAppInstallLocation());
+ mInstallLocation.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ String value = (String) newValue;
+ handleUpdateAppInstallLocation(value);
+ return false;
+ }
+ });
+ }
+
if (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_NOKEYS) {
// No hard keyboard, remove the setting for quick launch
Preference quickLaunchSetting = findPreference(KEY_QUICK_LAUNCH);
@@ -52,6 +83,24 @@
}
}
+ protected void handleUpdateAppInstallLocation(final String value) {
+ if(APP_INSTALL_DEVICE_ID.equals(value)) {
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.DEFAULT_INSTALL_LOCATION, APP_INSTALL_DEVICE);
+ } else if (APP_INSTALL_SDCARD_ID.equals(value)) {
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.DEFAULT_INSTALL_LOCATION, APP_INSTALL_SDCARD);
+ } else if (APP_INSTALL_AUTO_ID.equals(value)) {
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+ } else {
+ // Should not happen, default to prompt...
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+ }
+ mInstallLocation.setValue(value);
+ }
+
@Override
protected void onDestroy() {
super.onDestroy();
@@ -70,7 +119,7 @@
setNonMarketAppsAllowed(false);
}
}
-
+
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
@@ -92,6 +141,21 @@
Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0;
}
+ private String getAppInstallLocation() {
+ int selectedLocation = Settings.System.getInt(getContentResolver(),
+ Settings.System.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+ if (selectedLocation == APP_INSTALL_DEVICE) {
+ return APP_INSTALL_DEVICE_ID;
+ } else if (selectedLocation == APP_INSTALL_SDCARD) {
+ return APP_INSTALL_SDCARD_ID;
+ } else if (selectedLocation == APP_INSTALL_AUTO) {
+ return APP_INSTALL_AUTO_ID;
+ } else {
+ // Default value, should not happen.
+ return APP_INSTALL_AUTO_ID;
+ }
+ }
+
private void warnAppInstallation() {
mWarnInstallApps = new AlertDialog.Builder(this)
.setTitle(getString(R.string.error_title))
@@ -101,6 +165,4 @@
.setNegativeButton(android.R.string.no, null)
.show();
}
-
-
}
diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
index 126af6b..26ad70c 100644
--- a/src/com/android/settings/DeviceAdminAdd.java
+++ b/src/com/android/settings/DeviceAdminAdd.java
@@ -137,8 +137,18 @@
mActionButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mAdding) {
- mDPM.setActiveAdmin(mDeviceAdmin.getComponent());
- setResult(Activity.RESULT_OK);
+ try {
+ mDPM.setActiveAdmin(mDeviceAdmin.getComponent());
+ setResult(Activity.RESULT_OK);
+ } catch (RuntimeException e) {
+ // Something bad happened... could be that it was
+ // already set, though.
+ Log.w(TAG, "Exception trying to activate admin "
+ + mDeviceAdmin.getComponent(), e);
+ if (mDPM.isAdminActive(mDeviceAdmin.getComponent())) {
+ setResult(Activity.RESULT_OK);
+ }
+ }
finish();
} else {
mDPM.getRemoveWarning(mDeviceAdmin.getComponent(),
diff --git a/src/com/android/settings/InstalledAppDetails.java b/src/com/android/settings/InstalledAppDetails.java
index 1358133..67f2f8f 100644
--- a/src/com/android/settings/InstalledAppDetails.java
+++ b/src/com/android/settings/InstalledAppDetails.java
@@ -23,14 +23,14 @@
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
-import android.app.ActivityManager.RunningAppProcessInfo;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -42,7 +42,6 @@
import android.os.Message;
import android.os.RemoteException;
import android.text.format.Formatter;
-import android.util.Config;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
@@ -87,6 +86,7 @@
PackageStats mSizeInfo;
private PackageManager mPm;
+ private PackageMoveObserver mPackageMoveObserver;
//internal constants used in Handler
private static final int OP_SUCCESSFUL = 1;
@@ -94,6 +94,7 @@
private static final int CLEAR_USER_DATA = 1;
private static final int GET_PKG_SIZE = 2;
private static final int CLEAR_CACHE = 3;
+ private static final int PACKAGE_MOVE = 4;
private static final String ATTR_PACKAGE_STATS="PackageStats";
// invalid size value used initially and also when size retrieval through PackageManager
@@ -125,6 +126,9 @@
// Refresh size info
mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver);
break;
+ case PACKAGE_MOVE:
+ processMoveMsg(msg);
+ break;
default:
break;
}
@@ -153,10 +157,18 @@
class ClearCacheObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(final String packageName, final boolean succeeded) {
final Message msg = mHandler.obtainMessage(CLEAR_CACHE);
- msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
+ msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED;
mHandler.sendMessage(msg);
}
}
+
+ class PackageMoveObserver extends IPackageMoveObserver.Stub {
+ public void packageMoved(String packageName, int returnCode) throws RemoteException {
+ final Message msg = mHandler.obtainMessage(PACKAGE_MOVE);
+ msg.arg1 = returnCode;
+ mHandler.sendMessage(msg);
+ }
+ }
private String getSizeStr(long size) {
if (size == SIZE_INVALID) {
@@ -172,23 +184,36 @@
mClearDataButton.setText(R.string.clear_user_data_text);
}
mClearDataButton.setOnClickListener(this);
+ initMoveButton();
+ }
+
+ private void initMoveButton() {
String pkgName = mAppInfo.packageName;
boolean dataOnly = false;
ApplicationInfo info1 = null;
- ApplicationInfo info2 = null;
try {
info1 = mPm.getApplicationInfo(pkgName, 0);
} catch (NameNotFoundException e) {
}
dataOnly = (info1 == null) && (mAppInfo != null);
+ boolean moveDisable = true;
if (dataOnly) {
mMoveAppButton.setText(R.string.move_app);
} else if ((mAppInfo.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0) {
mMoveAppButton.setText(R.string.move_app_to_internal);
+ moveDisable = false;
} else {
+ moveDisable = (mAppInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0 ||
+ (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
mMoveAppButton.setText(R.string.move_app_to_sdcard);
}
+ if (moveDisable) {
+ mMoveAppButton.setEnabled(false);
+ } else {
+ mMoveAppButton.setOnClickListener(this);
+ mMoveAppButton.setEnabled(true);
+ }
}
private void initControlButtons() {
@@ -207,25 +232,6 @@
// Register listener
mUninstallButton.setOnClickListener(this);
}
- ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
- List<RunningAppProcessInfo> rList = am.getRunningAppProcesses();
- boolean running = false;
- if (rList != null) {
- for (RunningAppProcessInfo info : rList) {
- if (info.pkgList != null) {
- for (String rpkg : info.pkgList) {
- if (rpkg.equals(mAppInfo.packageName)) {
- running = true;
- break;
- }
- }
- }
- }
- }
- mForceStopButton.setEnabled(running);
- if (running) {
- mForceStopButton.setOnClickListener(this);
- }
}
/** Called when the activity is first created. */
@@ -265,13 +271,12 @@
mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button);
mForceStopButton.setText(R.string.force_stop);
mUninstallButton = (Button)btnPanel.findViewById(R.id.right_button);
+ mForceStopButton.setEnabled(false);
initControlButtons();
// Initialize clear data and move install location buttons
View data_buttons_panel = findViewById(R.id.data_buttons_panel);
mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.left_button);
mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.right_button);
- // Disable move for now
- mMoveAppButton.setEnabled(false);
// Cache section
mCacheSize = (TextView) findViewById(R.id.cache_size_text);
mCacheSize.setText(mComputingStr);
@@ -359,6 +364,7 @@
showDialogInner(DLG_APP_NOT_FOUND);
return;
}
+ checkForceStop();
refreshAppAttributes(pkgInfo);
}
@@ -444,6 +450,24 @@
mClearDataButton.setEnabled(true);
}
}
+
+ private void processMoveMsg(Message msg) {
+ int result = msg.arg1;
+ String packageName = mAppInfo.packageName;
+ if(result == PackageManager.MOVE_SUCCEEDED) {
+ Log.i(TAG, "Moved resources for " + packageName);
+ try {
+ // Reset flags
+ mAppInfo = mPm.getApplicationInfo(packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ initMoveButton();
+ } catch (NameNotFoundException e) {
+ // TODO error handling
+ }
+ } else {
+ // TODO Present a dialog indicating failure.
+ }
+ }
/*
* Private method to initiate clearing user data when the user clicks the clear data
@@ -561,8 +585,25 @@
ActivityManager am = (ActivityManager)getSystemService(
Context.ACTIVITY_SERVICE);
am.forceStopPackage(pkgName);
+ checkForceStop();
}
+ private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mForceStopButton.setEnabled(getResultCode() != RESULT_CANCELED);
+ }
+ };
+
+ private void checkForceStop() {
+ Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
+ Uri.fromParts("package", mAppInfo.packageName, null));
+ intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppInfo.packageName });
+ intent.putExtra(Intent.EXTRA_UID, mAppInfo.uid);
+ sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
+ Activity.RESULT_CANCELED, null, null);
+ }
+
/*
* Method implementing functionality of buttons clicked
* @see android.view.View.OnClickListener#onClick(android.view.View)
@@ -601,6 +642,15 @@
// that the button cannot be enabled or disabled since
// we do not have this info for now.
forceStopPackage(mAppInfo.packageName);
+ } else if (v == mMoveAppButton) {
+ if (mPackageMoveObserver == null) {
+ mPackageMoveObserver = new PackageMoveObserver();
+ }
+ int moveFlags = (mAppInfo.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0 ?
+ PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
+ mMoveAppButton.setText(R.string.moving);
+ mMoveAppButton.setEnabled(false);
+ mPm.movePackage(mAppInfo.packageName, mPackageMoveObserver, moveFlags);
}
}
}
diff --git a/src/com/android/settings/RunningServices.java b/src/com/android/settings/RunningServices.java
index 6c11ea0..4808aec 100644
--- a/src/com/android/settings/RunningServices.java
+++ b/src/com/android/settings/RunningServices.java
@@ -35,6 +35,9 @@
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
@@ -53,6 +56,7 @@
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
@@ -93,13 +97,16 @@
int mProcessBgColor;
+ LinearColorBar mColorBar;
TextView mBackgroundProcessText;
TextView mForegroundProcessText;
int mLastNumBackgroundProcesses = -1;
int mLastNumForegroundProcesses = -1;
+ int mLastNumServiceProcesses = -1;
long mLastBackgroundProcessMemory = -1;
long mLastForegroundProcessMemory = -1;
+ long mLastServiceProcessMemory = -1;
long mLastAvailMemory = -1;
Dialog mCurDialog;
@@ -392,6 +399,8 @@
long mBackgroundProcessMemory;
int mNumForegroundProcesses;
long mForegroundProcessMemory;
+ int mNumServiceProcesses;
+ long mServiceProcessMemory;
boolean update(Context context, ActivityManager am) {
final PackageManager pm = context.getPackageManager();
@@ -576,6 +585,7 @@
mAllProcessItems.addAll(mProcessItems);
mNumBackgroundProcesses = 0;
mNumForegroundProcesses = 0;
+ mNumServiceProcesses = 0;
NRP = mRunningProcesses.size();
for (int i=0; i<NRP; i++) {
ProcessItem proc = mRunningProcesses.valueAt(i);
@@ -590,13 +600,19 @@
ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
mNumForegroundProcesses++;
mAllProcessItems.add(proc);
+ } else {
+ Log.i(TAG, "Unknown non-service process: "
+ + proc.mProcessName + " #" + proc.mPid);
}
+ } else {
+ mNumServiceProcesses++;
}
}
try {
mBackgroundProcessMemory = 0;
mForegroundProcessMemory = 0;
+ mServiceProcessMemory = 0;
final int numProc = mAllProcessItems.size();
int[] pids = new int[numProc];
for (int i=0; i<numProc; i++) {
@@ -608,9 +624,8 @@
ProcessItem proc = mAllProcessItems.get(i);
changed |= proc.updateSize(context, mem[i], mSequence);
if (proc.mCurSeq == mSequence) {
- continue;
- }
- if (proc.mRunningProcessInfo.importance >=
+ mServiceProcessMemory += proc.mSize;
+ } else if (proc.mRunningProcessInfo.importance >=
ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
mBackgroundProcessMemory += proc.mSize;
} else if (proc.mRunningProcessInfo.importance <=
@@ -725,6 +740,67 @@
}
}
+ public static class LinearColorBar extends LinearLayout {
+ private float mRedRatio;
+ private float mYellowRatio;
+ private float mGreenRatio;
+
+ final Rect mRect = new Rect();
+ final Paint mPaint = new Paint();
+
+ public LinearColorBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setWillNotDraw(false);
+ mPaint.setStyle(Paint.Style.FILL);
+ }
+
+ public void setRatios(float red, float yellow, float green) {
+ mRedRatio = red;
+ mYellowRatio = yellow;
+ mGreenRatio = green;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ int width = getWidth();
+ mRect.top = 0;
+ mRect.bottom = getHeight();
+
+ int left = 0;
+
+ int right = left + (int)(width*mRedRatio);
+ if (left < right) {
+ mRect.left = left;
+ mRect.right = right;
+ mPaint.setColor(0xffff8080);
+ canvas.drawRect(mRect, mPaint);
+ width -= (right-left);
+ left = right;
+ }
+
+ right = left + (int)(width*mYellowRatio);
+ if (left < right) {
+ mRect.left = left;
+ mRect.right = right;
+ mPaint.setColor(0xffffff00);
+ canvas.drawRect(mRect, mPaint);
+ width -= (right-left);
+ left = right;
+ }
+
+ right = left + width;
+ if (left < right) {
+ mRect.left = left;
+ mRect.right = right;
+ mPaint.setColor(0xff80ff80);
+ canvas.drawRect(mRect, mPaint);
+ }
+ }
+ }
+
final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -823,6 +899,7 @@
setContentView(R.layout.running_services);
getListView().setDivider(null);
getListView().setAdapter(new ServiceListAdapter(mState));
+ mColorBar = (LinearColorBar)findViewById(R.id.color_bar);
mBackgroundProcessText = (TextView)findViewById(R.id.backgroundText);
mForegroundProcessText = (TextView)findViewById(R.id.foregroundText);
@@ -864,6 +941,14 @@
mForegroundProcessText.setText(getResources().getString(
R.string.service_foreground_processes, mLastNumForegroundProcesses, sizeStr));
}
+ mLastNumServiceProcesses = mState.mNumServiceProcesses;
+ mLastServiceProcessMemory = mState.mServiceProcessMemory;
+
+ float totalMem = mLastBackgroundProcessMemory
+ + mLastForegroundProcessMemory + mLastServiceProcessMemory;
+ mColorBar.setRatios(mLastForegroundProcessMemory/totalMem,
+ mLastServiceProcessMemory/totalMem,
+ mLastForegroundProcessMemory/totalMem);
}
@Override
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index fb2f6c9..5b60c45 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -71,7 +71,7 @@
private static final String KEY_LOCK_ENABLED = "lockenabled";
private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
- private static final String KEY_TACTILE_FEEDBACK_ENABLED = "tactilefeedback";
+ private static final String KEY_TACTILE_FEEDBACK_ENABLED = "unlock_tactile_feedback";
private static final String KEY_UNLOCK_METHOD = "unlock_method";
private static final int UPDATE_PASSWORD_REQUEST = 56;
private static final int CONFIRM_EXISTING_REQUEST = 57;
@@ -285,13 +285,10 @@
super.onResume();
final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
- boolean patternExists = lockPatternUtils.savedPatternExists();
if (mVisiblePattern != null) {
- mVisiblePattern.setEnabled(patternExists);
mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled());
}
if (mTactileFeedback != null) {
- mTactileFeedback.setEnabled(patternExists);
mTactileFeedback.setChecked(lockPatternUtils.isTactileFeedbackEnabled());
}
diff --git a/src/com/android/settings/VoiceInputOutputSettings.java b/src/com/android/settings/VoiceInputOutputSettings.java
index 4011038..87e423c 100644
--- a/src/com/android/settings/VoiceInputOutputSettings.java
+++ b/src/com/android/settings/VoiceInputOutputSettings.java
@@ -100,7 +100,8 @@
ResolveInfo resolveInfo = availableRecognitionServices.get(0);
String recognizerComponent =
new ComponentName(resolveInfo.serviceInfo.packageName,
- resolveInfo.serviceInfo.name).flattenToString();
+ resolveInfo.serviceInfo.name).flattenToShortString();
+
mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
String currentSetting = Settings.Secure.getString(
@@ -134,7 +135,7 @@
ResolveInfo resolveInfo = recognizers.get(i);
String recognizerComponent =
new ComponentName(resolveInfo.serviceInfo.packageName,
- resolveInfo.serviceInfo.name).flattenToString();
+ resolveInfo.serviceInfo.name).flattenToShortString();
mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageDetail.java b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
index a98bfed..da5721a 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
@@ -18,6 +18,9 @@
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ApplicationErrorReport;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -26,9 +29,12 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Bundle;
+import android.os.Process;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -37,6 +43,7 @@
import android.widget.TextView;
import com.android.settings.InstalledAppDetails;
+import com.android.settings.ManageApplications;
import com.android.settings.R;
public class PowerUsageDetail extends Activity implements Button.OnClickListener {
@@ -68,6 +75,8 @@
public static final int ACTION_WIRELESS_SETTINGS = 4;
public static final int ACTION_APP_DETAILS = 5;
public static final int ACTION_SECURITY_SETTINGS = 6;
+ public static final int ACTION_FORCE_STOP = 7;
+ public static final int ACTION_REPORT = 8;
public static final int USAGE_SINCE_UNPLUGGED = 1;
public static final int USAGE_SINCE_RESET = 2;
@@ -78,6 +87,8 @@
public static final String EXTRA_UID = "uid";
public static final String EXTRA_USAGE_SINCE = "since";
public static final String EXTRA_USAGE_DURATION = "duration";
+ public static final String EXTRA_REPORT_DETAILS = "report_details";
+ public static final String EXTRA_REPORT_CHECKIN_DETAILS = "report_checkin_details";
public static final String EXTRA_DETAIL_TYPES = "types"; // Array of usage types (cpu, gps, etc)
public static final String EXTRA_DETAIL_VALUES = "values"; // Array of doubles
public static final String EXTRA_DRAIN_TYPE = "drainType"; // DrainType
@@ -92,6 +103,9 @@
private int mUid;
private double[] mValues;
private TextView mTitleView;
+ private ViewGroup mTwoButtonsPanel;
+ private Button mForceStopButton;
+ private Button mReportButton;
private ViewGroup mDetailsParent;
private ViewGroup mControlsParent;
private long mStartTime;
@@ -105,6 +119,9 @@
private static final String TAG = "PowerUsageDetail";
private String[] mPackages;
+ ApplicationInfo mApp;
+ ComponentName mInstaller;
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -116,6 +133,7 @@
protected void onResume() {
super.onResume();
mStartTime = android.os.Process.getElapsedCpuTime();
+ checkForceStop();
}
@Override
@@ -163,6 +181,11 @@
((TextView)findViewById(R.id.battery_percentage))
.setText(String.format("%d%%", percentage));
+ mTwoButtonsPanel = (ViewGroup) findViewById(R.id.two_buttons_panel);
+ mForceStopButton = (Button) findViewById(R.id.left_button);
+ mReportButton = (Button) findViewById(R.id.right_button);
+ mForceStopButton.setEnabled(false);
+
ImageView gaugeImage = (ImageView) findViewById(R.id.gauge);
mGauge = new PercentageBar();
mGauge.percent = gaugeValue;
@@ -178,6 +201,34 @@
fillDetailsSection();
fillPackagesSection(mUid);
fillControlsSection(mUid);
+
+ if (mUid >= Process.FIRST_APPLICATION_UID) {
+ mForceStopButton.setText(R.string.force_stop);
+ mForceStopButton.setTag(ACTION_FORCE_STOP);
+ mForceStopButton.setOnClickListener(this);
+ mReportButton.setText(com.android.internal.R.string.report);
+ mReportButton.setTag(ACTION_REPORT);
+ mReportButton.setOnClickListener(this);
+
+ // check if error reporting is enabled in secure settings
+ int enabled = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.SEND_ACTION_APP_ERROR, 0);
+ if (enabled != 0) {
+ if (mPackages != null && mPackages.length > 0) {
+ try {
+ mApp = getPackageManager().getApplicationInfo(mPackages[0], 0);
+ mInstaller = ApplicationErrorReport.getErrorReportReceiver(
+ this, mPackages[0], mApp.flags);
+ } catch (NameNotFoundException e) {
+ }
+ }
+ mReportButton.setEnabled(mInstaller != null);
+ } else {
+ mTwoButtonsPanel.setVisibility(View.GONE);
+ }
+ } else {
+ mTwoButtonsPanel.setVisibility(View.GONE);
+ }
}
public void onClick(View v) {
@@ -201,12 +252,18 @@
case ACTION_APP_DETAILS:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(this, InstalledAppDetails.class);
- intent.putExtra("com.android.settings.ApplicationPkgName", mPackages[0]);
+ intent.putExtra(ManageApplications.APP_PKG_NAME, mPackages[0]);
startActivity(intent);
break;
case ACTION_SECURITY_SETTINGS:
startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
break;
+ case ACTION_FORCE_STOP:
+ killProcesses();
+ break;
+ case ACTION_REPORT:
+ reportBatteryUse();
+ break;
}
}
@@ -332,8 +389,62 @@
for (int i = 0; i < mPackages.length; i++) {
am.forceStopPackage(mPackages[i]);
}
+ checkForceStop();
}
+ private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mForceStopButton.setEnabled(getResultCode() != RESULT_CANCELED);
+ }
+ };
+
+ private void checkForceStop() {
+ if (mPackages == null || mUid < Process.FIRST_APPLICATION_UID) {
+ mForceStopButton.setEnabled(false);
+ return;
+ }
+ Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
+ Uri.fromParts("package", mPackages[0], null));
+ intent.putExtra(Intent.EXTRA_PACKAGES, mPackages);
+ intent.putExtra(Intent.EXTRA_UID, mUid);
+ sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
+ Activity.RESULT_CANCELED, null, null);
+ }
+
+ private void reportBatteryUse() {
+ if (mPackages == null) return;
+
+ final Intent intent = getIntent();
+ final int percentage = intent.getIntExtra(EXTRA_PERCENT, 1);
+ final long duration = intent.getLongExtra(EXTRA_USAGE_DURATION, 0);
+
+ ApplicationErrorReport report = new ApplicationErrorReport();
+ report.type = ApplicationErrorReport.TYPE_BATTERY;
+ report.packageName = mPackages[0];
+ report.installerPackageName = mInstaller.getPackageName();
+ report.processName = mPackages[0];
+ report.time = System.currentTimeMillis();
+ report.systemApp = (mApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+
+ StringBuilder builder = new StringBuilder();
+ builder.append("Application used " + percentage + "% of battery over "
+ + Utils.formatElapsedTime(this, duration / 1000));
+ builder.append('\n');
+ builder.append(intent.getStringExtra(EXTRA_REPORT_DETAILS));
+ builder.append('\n');
+ builder.append("----------------------------------------------");
+ builder.append('\n');
+ builder.append(intent.getStringExtra(EXTRA_REPORT_CHECKIN_DETAILS));
+ builder.append('\n');
+ report.batteryText = builder.toString();
+ Intent result = new Intent(Intent.ACTION_APP_ERROR);
+ result.setComponent(mInstaller);
+ result.putExtra(Intent.EXTRA_BUG_REPORT, report);
+ result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(result);
+ }
+
private void fillPackagesSection(int uid) {
if (uid < 1) {
removePackagesSection();
@@ -344,7 +455,7 @@
LayoutInflater inflater = getLayoutInflater();
PackageManager pm = getPackageManager();
- final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
+ //final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
mPackages = pm.getPackagesForUid(uid);
if (mPackages == null || mPackages.length < 2) {
removePackagesSection();
@@ -356,13 +467,13 @@
try {
ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0);
CharSequence label = ai.loadLabel(pm);
- Drawable icon = defaultActivityIcon;
+ //Drawable icon = defaultActivityIcon;
if (label != null) {
mPackages[i] = label.toString();
}
- if (ai.icon != 0) {
- icon = ai.loadIcon(pm);
- }
+ //if (ai.icon != 0) {
+ // icon = ai.loadIcon(pm);
+ //}
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_package_item,
null);
packagesParent.addView(item);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 10ab2d0..5678160 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -48,6 +48,9 @@
import com.android.settings.R;
import com.android.settings.fuelgauge.PowerUsageDetail.DrainType;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -78,6 +81,7 @@
private static final int MIN_POWER_THRESHOLD = 5;
private static final int MAX_ITEMS_TO_LIST = 10;
+ private long mStatsPeriod = 0;
private double mMaxPower = 1;
private double mTotalPower;
private PowerProfile mPowerProfile;
@@ -132,6 +136,7 @@
Math.ceil(sipper.getSortValue() * 100 / mTotalPower));
intent.putExtra(PowerUsageDetail.EXTRA_GAUGE, (int)
Math.ceil(sipper.getSortValue() * 100 / mMaxPower));
+ intent.putExtra(PowerUsageDetail.EXTRA_USAGE_DURATION, mStatsPeriod);
intent.putExtra(PowerUsageDetail.EXTRA_ICON_PACKAGE, sipper.defaultPackageName);
intent.putExtra(PowerUsageDetail.EXTRA_ICON_ID, sipper.iconId);
intent.putExtra(PowerUsageDetail.EXTRA_NO_COVERAGE, sipper.noCoveragePercent);
@@ -165,6 +170,15 @@
0
};
+ Writer result = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(result);
+ mStats.dumpLocked(printWriter, "", mStatsType, uid.getUid());
+ intent.putExtra(PowerUsageDetail.EXTRA_REPORT_DETAILS, result.toString());
+
+ result = new StringWriter();
+ printWriter = new PrintWriter(result);
+ mStats.dumpCheckinLocked(printWriter, mStatsType, uid.getUid());
+ intent.putExtra(PowerUsageDetail.EXTRA_REPORT_CHECKIN_DETAILS, result.toString());
}
break;
case CELL:
@@ -303,6 +317,7 @@
}
final double averageCostPerByte = getAverageDataCost();
long uSecTime = mStats.computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
+ mStatsPeriod = uSecTime;
updateStatsPeriod(uSecTime);
SparseArray<? extends Uid> uidStats = mStats.getUidStats();
final int NU = uidStats.size();