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"/>
</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" />
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"
android:textAppearance="?android:attr/textAppearanceSmallInverse"
android:color="?android:attr/textColorPrimaryInverse"
android:singleLine="true" />
- </LinearLayout>
+ </view>
</LinearLayout>
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.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;
// 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. */
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);
showDialogInner(DLG_APP_NOT_FOUND);
return;
}
+ checkForceStop();
refreshAppAttributes(pkgInfo);
}
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)
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;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
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;
long mBackgroundProcessMemory;
int mNumForegroundProcesses;
long mForegroundProcessMemory;
+ int mNumServiceProcesses;
+ long mServiceProcessMemory;
boolean update(Context context, ActivityManager am) {
final PackageManager pm = context.getPackageManager();
mAllProcessItems.addAll(mProcessItems);
mNumBackgroundProcesses = 0;
mNumForegroundProcesses = 0;
+ mNumServiceProcesses = 0;
NRP = mRunningProcesses.size();
for (int i=0; i<NRP; i++) {
ProcessItem proc = mRunningProcesses.valueAt(i);
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++) {
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 <=
}
}
+ 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) {
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);
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
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;
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;
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 {
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;
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
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;
private static final String TAG = "PowerUsageDetail";
private String[] mPackages;
+ ApplicationInfo mApp;
+ ComponentName mInstaller;
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
protected void onResume() {
super.onResume();
mStartTime = android.os.Process.getElapsedCpuTime();
+ checkForceStop();
}
@Override
((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;
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) {
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;
}
}
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();
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();
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);
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;
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;
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);
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:
}
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();