Add new button to report battery usage to the developer.
This displays a new button on the application battery usage details screen for the user to send a bug report to the developer, if that is possible to do. Also adds a button to directly force stop the app from the details screen, and uses the new facilities to determine whether the button should be enabled.
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="2dip"
|
android:layout_marginTop="2dip"
|
||||||
|
android:paddingBottom="4dip"
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="marquee"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||||
|
|
||||||
|
@@ -87,6 +87,17 @@
|
|||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</LinearLayout>
|
</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
|
<TextView
|
||||||
style="?android:attr/listSeparatorTextViewStyle"
|
style="?android:attr/listSeparatorTextViewStyle"
|
||||||
android:text="@string/details_subtitle" />
|
android:text="@string/details_subtitle" />
|
||||||
|
@@ -35,20 +35,20 @@
|
|||||||
android:text="@string/no_running_services"
|
android:text="@string/no_running_services"
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
<LinearLayout
|
<view class="com.android.settings.RunningServices$LinearColorBar"
|
||||||
|
android:id="@+id/color_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:background="?android:attr/colorForeground"
|
|
||||||
android:padding="4dp">
|
android:padding="4dp">
|
||||||
<TextView android:id="@+id/backgroundText"
|
<TextView android:id="@+id/foregroundText"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmallInverse"
|
android:textAppearance="?android:attr/textAppearanceSmallInverse"
|
||||||
android:color="?android:attr/textColorPrimaryInverse"
|
android:color="?android:attr/textColorPrimaryInverse"
|
||||||
android:singleLine="true" />
|
android:singleLine="true" />
|
||||||
<TextView android:id="@+id/foregroundText"
|
<TextView android:id="@+id/backgroundText"
|
||||||
android:layout_gravity="center_vertical|right"
|
android:layout_gravity="center_vertical|right"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -56,5 +56,5 @@
|
|||||||
android:textAppearance="?android:attr/textAppearanceSmallInverse"
|
android:textAppearance="?android:attr/textAppearanceSmallInverse"
|
||||||
android:color="?android:attr/textColorPrimaryInverse"
|
android:color="?android:attr/textColorPrimaryInverse"
|
||||||
android:singleLine="true" />
|
android:singleLine="true" />
|
||||||
</LinearLayout>
|
</view>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@@ -23,14 +23,13 @@ import android.app.Activity;
|
|||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.ActivityManager.RunningAppProcessInfo;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.IPackageDataObserver;
|
import android.content.pm.IPackageDataObserver;
|
||||||
import android.content.pm.IPackageDeleteObserver;
|
|
||||||
import android.content.pm.IPackageMoveObserver;
|
import android.content.pm.IPackageMoveObserver;
|
||||||
import android.content.pm.IPackageStatsObserver;
|
import android.content.pm.IPackageStatsObserver;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
@@ -43,7 +42,6 @@ import android.os.Handler;
|
|||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.text.format.Formatter;
|
import android.text.format.Formatter;
|
||||||
import android.util.Config;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -234,25 +232,6 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
|
|||||||
// Register listener
|
// Register listener
|
||||||
mUninstallButton.setOnClickListener(this);
|
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. */
|
/** Called when the activity is first created. */
|
||||||
@@ -292,6 +271,7 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
|
|||||||
mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button);
|
mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button);
|
||||||
mForceStopButton.setText(R.string.force_stop);
|
mForceStopButton.setText(R.string.force_stop);
|
||||||
mUninstallButton = (Button)btnPanel.findViewById(R.id.right_button);
|
mUninstallButton = (Button)btnPanel.findViewById(R.id.right_button);
|
||||||
|
mForceStopButton.setEnabled(false);
|
||||||
initControlButtons();
|
initControlButtons();
|
||||||
// Initialize clear data and move install location buttons
|
// Initialize clear data and move install location buttons
|
||||||
View data_buttons_panel = findViewById(R.id.data_buttons_panel);
|
View data_buttons_panel = findViewById(R.id.data_buttons_panel);
|
||||||
@@ -384,6 +364,7 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
|
|||||||
showDialogInner(DLG_APP_NOT_FOUND);
|
showDialogInner(DLG_APP_NOT_FOUND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
checkForceStop();
|
||||||
refreshAppAttributes(pkgInfo);
|
refreshAppAttributes(pkgInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,6 +585,23 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
|
|||||||
ActivityManager am = (ActivityManager)getSystemService(
|
ActivityManager am = (ActivityManager)getSystemService(
|
||||||
Context.ACTIVITY_SERVICE);
|
Context.ACTIVITY_SERVICE);
|
||||||
am.forceStopPackage(pkgName);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -35,6 +35,9 @@ import android.content.pm.PackageItemInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -53,6 +56,7 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.AbsListView;
|
import android.widget.AbsListView;
|
||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
@@ -93,13 +97,16 @@ public class RunningServices extends ListActivity
|
|||||||
|
|
||||||
int mProcessBgColor;
|
int mProcessBgColor;
|
||||||
|
|
||||||
|
LinearColorBar mColorBar;
|
||||||
TextView mBackgroundProcessText;
|
TextView mBackgroundProcessText;
|
||||||
TextView mForegroundProcessText;
|
TextView mForegroundProcessText;
|
||||||
|
|
||||||
int mLastNumBackgroundProcesses = -1;
|
int mLastNumBackgroundProcesses = -1;
|
||||||
int mLastNumForegroundProcesses = -1;
|
int mLastNumForegroundProcesses = -1;
|
||||||
|
int mLastNumServiceProcesses = -1;
|
||||||
long mLastBackgroundProcessMemory = -1;
|
long mLastBackgroundProcessMemory = -1;
|
||||||
long mLastForegroundProcessMemory = -1;
|
long mLastForegroundProcessMemory = -1;
|
||||||
|
long mLastServiceProcessMemory = -1;
|
||||||
long mLastAvailMemory = -1;
|
long mLastAvailMemory = -1;
|
||||||
|
|
||||||
Dialog mCurDialog;
|
Dialog mCurDialog;
|
||||||
@@ -392,6 +399,8 @@ public class RunningServices extends ListActivity
|
|||||||
long mBackgroundProcessMemory;
|
long mBackgroundProcessMemory;
|
||||||
int mNumForegroundProcesses;
|
int mNumForegroundProcesses;
|
||||||
long mForegroundProcessMemory;
|
long mForegroundProcessMemory;
|
||||||
|
int mNumServiceProcesses;
|
||||||
|
long mServiceProcessMemory;
|
||||||
|
|
||||||
boolean update(Context context, ActivityManager am) {
|
boolean update(Context context, ActivityManager am) {
|
||||||
final PackageManager pm = context.getPackageManager();
|
final PackageManager pm = context.getPackageManager();
|
||||||
@@ -576,6 +585,7 @@ public class RunningServices extends ListActivity
|
|||||||
mAllProcessItems.addAll(mProcessItems);
|
mAllProcessItems.addAll(mProcessItems);
|
||||||
mNumBackgroundProcesses = 0;
|
mNumBackgroundProcesses = 0;
|
||||||
mNumForegroundProcesses = 0;
|
mNumForegroundProcesses = 0;
|
||||||
|
mNumServiceProcesses = 0;
|
||||||
NRP = mRunningProcesses.size();
|
NRP = mRunningProcesses.size();
|
||||||
for (int i=0; i<NRP; i++) {
|
for (int i=0; i<NRP; i++) {
|
||||||
ProcessItem proc = mRunningProcesses.valueAt(i);
|
ProcessItem proc = mRunningProcesses.valueAt(i);
|
||||||
@@ -590,13 +600,19 @@ public class RunningServices extends ListActivity
|
|||||||
ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
|
ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
|
||||||
mNumForegroundProcesses++;
|
mNumForegroundProcesses++;
|
||||||
mAllProcessItems.add(proc);
|
mAllProcessItems.add(proc);
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "Unknown non-service process: "
|
||||||
|
+ proc.mProcessName + " #" + proc.mPid);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
mNumServiceProcesses++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mBackgroundProcessMemory = 0;
|
mBackgroundProcessMemory = 0;
|
||||||
mForegroundProcessMemory = 0;
|
mForegroundProcessMemory = 0;
|
||||||
|
mServiceProcessMemory = 0;
|
||||||
final int numProc = mAllProcessItems.size();
|
final int numProc = mAllProcessItems.size();
|
||||||
int[] pids = new int[numProc];
|
int[] pids = new int[numProc];
|
||||||
for (int i=0; i<numProc; i++) {
|
for (int i=0; i<numProc; i++) {
|
||||||
@@ -608,9 +624,8 @@ public class RunningServices extends ListActivity
|
|||||||
ProcessItem proc = mAllProcessItems.get(i);
|
ProcessItem proc = mAllProcessItems.get(i);
|
||||||
changed |= proc.updateSize(context, mem[i], mSequence);
|
changed |= proc.updateSize(context, mem[i], mSequence);
|
||||||
if (proc.mCurSeq == mSequence) {
|
if (proc.mCurSeq == mSequence) {
|
||||||
continue;
|
mServiceProcessMemory += proc.mSize;
|
||||||
}
|
} else if (proc.mRunningProcessInfo.importance >=
|
||||||
if (proc.mRunningProcessInfo.importance >=
|
|
||||||
ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
|
ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
|
||||||
mBackgroundProcessMemory += proc.mSize;
|
mBackgroundProcessMemory += proc.mSize;
|
||||||
} else if (proc.mRunningProcessInfo.importance <=
|
} else if (proc.mRunningProcessInfo.importance <=
|
||||||
@@ -725,6 +740,67 @@ public class RunningServices extends ListActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
final Handler mHandler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
@@ -823,6 +899,7 @@ public class RunningServices extends ListActivity
|
|||||||
setContentView(R.layout.running_services);
|
setContentView(R.layout.running_services);
|
||||||
getListView().setDivider(null);
|
getListView().setDivider(null);
|
||||||
getListView().setAdapter(new ServiceListAdapter(mState));
|
getListView().setAdapter(new ServiceListAdapter(mState));
|
||||||
|
mColorBar = (LinearColorBar)findViewById(R.id.color_bar);
|
||||||
mBackgroundProcessText = (TextView)findViewById(R.id.backgroundText);
|
mBackgroundProcessText = (TextView)findViewById(R.id.backgroundText);
|
||||||
mForegroundProcessText = (TextView)findViewById(R.id.foregroundText);
|
mForegroundProcessText = (TextView)findViewById(R.id.foregroundText);
|
||||||
|
|
||||||
@@ -864,6 +941,14 @@ public class RunningServices extends ListActivity
|
|||||||
mForegroundProcessText.setText(getResources().getString(
|
mForegroundProcessText.setText(getResources().getString(
|
||||||
R.string.service_foreground_processes, mLastNumForegroundProcesses, sizeStr));
|
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
|
@Override
|
||||||
|
@@ -18,6 +18,9 @@ package com.android.settings.fuelgauge;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
|
import android.app.ApplicationErrorReport;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
@@ -26,9 +29,12 @@ import android.content.pm.PackageManager;
|
|||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Process;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -37,6 +43,7 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.android.settings.InstalledAppDetails;
|
import com.android.settings.InstalledAppDetails;
|
||||||
|
import com.android.settings.ManageApplications;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
public class PowerUsageDetail extends Activity implements Button.OnClickListener {
|
public class PowerUsageDetail extends Activity implements Button.OnClickListener {
|
||||||
@@ -68,6 +75,8 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
|
|||||||
public static final int ACTION_WIRELESS_SETTINGS = 4;
|
public static final int ACTION_WIRELESS_SETTINGS = 4;
|
||||||
public static final int ACTION_APP_DETAILS = 5;
|
public static final int ACTION_APP_DETAILS = 5;
|
||||||
public static final int ACTION_SECURITY_SETTINGS = 6;
|
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_UNPLUGGED = 1;
|
||||||
public static final int USAGE_SINCE_RESET = 2;
|
public static final int USAGE_SINCE_RESET = 2;
|
||||||
@@ -78,6 +87,8 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
|
|||||||
public static final String EXTRA_UID = "uid";
|
public static final String EXTRA_UID = "uid";
|
||||||
public static final String EXTRA_USAGE_SINCE = "since";
|
public static final String EXTRA_USAGE_SINCE = "since";
|
||||||
public static final String EXTRA_USAGE_DURATION = "duration";
|
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_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_DETAIL_VALUES = "values"; // Array of doubles
|
||||||
public static final String EXTRA_DRAIN_TYPE = "drainType"; // DrainType
|
public static final String EXTRA_DRAIN_TYPE = "drainType"; // DrainType
|
||||||
@@ -92,6 +103,9 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
|
|||||||
private int mUid;
|
private int mUid;
|
||||||
private double[] mValues;
|
private double[] mValues;
|
||||||
private TextView mTitleView;
|
private TextView mTitleView;
|
||||||
|
private ViewGroup mTwoButtonsPanel;
|
||||||
|
private Button mForceStopButton;
|
||||||
|
private Button mReportButton;
|
||||||
private ViewGroup mDetailsParent;
|
private ViewGroup mDetailsParent;
|
||||||
private ViewGroup mControlsParent;
|
private ViewGroup mControlsParent;
|
||||||
private long mStartTime;
|
private long mStartTime;
|
||||||
@@ -105,6 +119,9 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
|
|||||||
private static final String TAG = "PowerUsageDetail";
|
private static final String TAG = "PowerUsageDetail";
|
||||||
private String[] mPackages;
|
private String[] mPackages;
|
||||||
|
|
||||||
|
ApplicationInfo mApp;
|
||||||
|
ComponentName mInstaller;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle icicle) {
|
protected void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
@@ -116,6 +133,7 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
|
|||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
mStartTime = android.os.Process.getElapsedCpuTime();
|
mStartTime = android.os.Process.getElapsedCpuTime();
|
||||||
|
checkForceStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -163,6 +181,11 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
|
|||||||
((TextView)findViewById(R.id.battery_percentage))
|
((TextView)findViewById(R.id.battery_percentage))
|
||||||
.setText(String.format("%d%%", 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);
|
ImageView gaugeImage = (ImageView) findViewById(R.id.gauge);
|
||||||
mGauge = new PercentageBar();
|
mGauge = new PercentageBar();
|
||||||
mGauge.percent = gaugeValue;
|
mGauge.percent = gaugeValue;
|
||||||
@@ -178,6 +201,34 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
|
|||||||
fillDetailsSection();
|
fillDetailsSection();
|
||||||
fillPackagesSection(mUid);
|
fillPackagesSection(mUid);
|
||||||
fillControlsSection(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) {
|
public void onClick(View v) {
|
||||||
@@ -201,12 +252,18 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
|
|||||||
case ACTION_APP_DETAILS:
|
case ACTION_APP_DETAILS:
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
intent.setClass(this, InstalledAppDetails.class);
|
intent.setClass(this, InstalledAppDetails.class);
|
||||||
intent.putExtra("com.android.settings.ApplicationPkgName", mPackages[0]);
|
intent.putExtra(ManageApplications.APP_PKG_NAME, mPackages[0]);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
break;
|
break;
|
||||||
case ACTION_SECURITY_SETTINGS:
|
case ACTION_SECURITY_SETTINGS:
|
||||||
startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
|
startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
|
||||||
break;
|
break;
|
||||||
|
case ACTION_FORCE_STOP:
|
||||||
|
killProcesses();
|
||||||
|
break;
|
||||||
|
case ACTION_REPORT:
|
||||||
|
reportBatteryUse();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,6 +389,60 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
|
|||||||
for (int i = 0; i < mPackages.length; i++) {
|
for (int i = 0; i < mPackages.length; i++) {
|
||||||
am.forceStopPackage(mPackages[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) {
|
private void fillPackagesSection(int uid) {
|
||||||
@@ -344,7 +455,7 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
|
|||||||
LayoutInflater inflater = getLayoutInflater();
|
LayoutInflater inflater = getLayoutInflater();
|
||||||
|
|
||||||
PackageManager pm = getPackageManager();
|
PackageManager pm = getPackageManager();
|
||||||
final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
|
//final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
|
||||||
mPackages = pm.getPackagesForUid(uid);
|
mPackages = pm.getPackagesForUid(uid);
|
||||||
if (mPackages == null || mPackages.length < 2) {
|
if (mPackages == null || mPackages.length < 2) {
|
||||||
removePackagesSection();
|
removePackagesSection();
|
||||||
@@ -356,13 +467,13 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
|
|||||||
try {
|
try {
|
||||||
ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0);
|
ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0);
|
||||||
CharSequence label = ai.loadLabel(pm);
|
CharSequence label = ai.loadLabel(pm);
|
||||||
Drawable icon = defaultActivityIcon;
|
//Drawable icon = defaultActivityIcon;
|
||||||
if (label != null) {
|
if (label != null) {
|
||||||
mPackages[i] = label.toString();
|
mPackages[i] = label.toString();
|
||||||
}
|
}
|
||||||
if (ai.icon != 0) {
|
//if (ai.icon != 0) {
|
||||||
icon = ai.loadIcon(pm);
|
// icon = ai.loadIcon(pm);
|
||||||
}
|
//}
|
||||||
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_package_item,
|
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_package_item,
|
||||||
null);
|
null);
|
||||||
packagesParent.addView(item);
|
packagesParent.addView(item);
|
||||||
|
@@ -48,6 +48,9 @@ import com.android.internal.os.PowerProfile;
|
|||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.fuelgauge.PowerUsageDetail.DrainType;
|
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.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -78,6 +81,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
|
|||||||
private static final int MIN_POWER_THRESHOLD = 5;
|
private static final int MIN_POWER_THRESHOLD = 5;
|
||||||
private static final int MAX_ITEMS_TO_LIST = 10;
|
private static final int MAX_ITEMS_TO_LIST = 10;
|
||||||
|
|
||||||
|
private long mStatsPeriod = 0;
|
||||||
private double mMaxPower = 1;
|
private double mMaxPower = 1;
|
||||||
private double mTotalPower;
|
private double mTotalPower;
|
||||||
private PowerProfile mPowerProfile;
|
private PowerProfile mPowerProfile;
|
||||||
@@ -132,6 +136,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
|
|||||||
Math.ceil(sipper.getSortValue() * 100 / mTotalPower));
|
Math.ceil(sipper.getSortValue() * 100 / mTotalPower));
|
||||||
intent.putExtra(PowerUsageDetail.EXTRA_GAUGE, (int)
|
intent.putExtra(PowerUsageDetail.EXTRA_GAUGE, (int)
|
||||||
Math.ceil(sipper.getSortValue() * 100 / mMaxPower));
|
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_PACKAGE, sipper.defaultPackageName);
|
||||||
intent.putExtra(PowerUsageDetail.EXTRA_ICON_ID, sipper.iconId);
|
intent.putExtra(PowerUsageDetail.EXTRA_ICON_ID, sipper.iconId);
|
||||||
intent.putExtra(PowerUsageDetail.EXTRA_NO_COVERAGE, sipper.noCoveragePercent);
|
intent.putExtra(PowerUsageDetail.EXTRA_NO_COVERAGE, sipper.noCoveragePercent);
|
||||||
@@ -165,6 +170,15 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
|
|||||||
0
|
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;
|
break;
|
||||||
case CELL:
|
case CELL:
|
||||||
@@ -303,6 +317,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
|
|||||||
}
|
}
|
||||||
final double averageCostPerByte = getAverageDataCost();
|
final double averageCostPerByte = getAverageDataCost();
|
||||||
long uSecTime = mStats.computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
|
long uSecTime = mStats.computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
|
||||||
|
mStatsPeriod = uSecTime;
|
||||||
updateStatsPeriod(uSecTime);
|
updateStatsPeriod(uSecTime);
|
||||||
SparseArray<? extends Uid> uidStats = mStats.getUidStats();
|
SparseArray<? extends Uid> uidStats = mStats.getUidStats();
|
||||||
final int NU = uidStats.size();
|
final int NU = uidStats.size();
|
||||||
|
Reference in New Issue
Block a user