This commit *only* changes imports and optimize imports. We don't do anything else. This patch can't compile pass and run test case. We will update other patches to fix these problem. Change list. 1. import android.app.Fragment; -> import androidx.fragment.app.Fragment; 2. import android.app.DialogFragment; -> import androidx.fragment.app.DialogFragment; 3. import android.app.ListFragment; -> import androidx.fragment.app.ListFragment; 4. import android.app.LoaderManager; -> import androidx.loader.app.LoaderManager; 5. import android.content.AsyncTaskLoader; -> import androidx.loader.content.AsyncTaskLoader; 6. import android.content.Loader; -> import androidx.loader.content.Loader; 7. import android.app.FragmentTransaction; -> import androidx.fragment.app.FragmentTransaction; 8. import android.app.FragmentManager; -> import androidx.fragment.app.FragmentManager; 9. import android.app.LoaderManager.LoaderCallbacks; -> import androidx.loader.app.LoaderManager.LoaderCallbacks; Bug: 110259478 Test: Can't test it. Change-Id: I0a3f98fff34a3494a839c3c42aeabcec3df2c8b3
658 lines
26 KiB
Java
658 lines
26 KiB
Java
package com.android.settings.applications;
|
|
|
|
import android.app.Activity;
|
|
import android.app.ActivityManager;
|
|
import android.app.AlertDialog;
|
|
import android.app.ApplicationErrorReport;
|
|
import android.app.Dialog;
|
|
import android.app.PendingIntent;
|
|
import android.content.ActivityNotFoundException;
|
|
import android.content.ComponentName;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.content.IntentSender;
|
|
import android.content.pm.ApplicationInfo;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.PackageManager.NameNotFoundException;
|
|
import android.content.pm.ProviderInfo;
|
|
import android.content.pm.ServiceInfo;
|
|
import android.content.res.Resources;
|
|
import android.os.Bundle;
|
|
import android.os.Debug;
|
|
import android.os.SystemClock;
|
|
import android.os.UserHandle;
|
|
import android.provider.Settings;
|
|
import android.util.Log;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.widget.Button;
|
|
import android.widget.TextView;
|
|
|
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
|
import com.android.settings.R;
|
|
import com.android.settings.Utils;
|
|
import com.android.settings.core.InstrumentedFragment;
|
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
|
import com.android.settingslib.utils.ThreadUtils;
|
|
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
|
|
import androidx.fragment.app.DialogFragment;
|
|
|
|
public class RunningServiceDetails extends InstrumentedFragment
|
|
implements RunningState.OnRefreshUiListener {
|
|
static final String TAG = "RunningServicesDetails";
|
|
|
|
static final String KEY_UID = "uid";
|
|
static final String KEY_USER_ID = "user_id";
|
|
static final String KEY_PROCESS = "process";
|
|
static final String KEY_BACKGROUND = "background";
|
|
|
|
static final int DIALOG_CONFIRM_STOP = 1;
|
|
|
|
ActivityManager mAm;
|
|
LayoutInflater mInflater;
|
|
|
|
RunningState mState;
|
|
boolean mHaveData;
|
|
|
|
int mUid;
|
|
int mUserId;
|
|
String mProcessName;
|
|
boolean mShowBackground;
|
|
|
|
RunningState.MergedItem mMergedItem;
|
|
|
|
View mRootView;
|
|
ViewGroup mAllDetails;
|
|
ViewGroup mSnippet;
|
|
RunningProcessesView.ActiveItem mSnippetActiveItem;
|
|
RunningProcessesView.ViewHolder mSnippetViewHolder;
|
|
|
|
int mNumServices, mNumProcesses;
|
|
|
|
TextView mServicesHeader;
|
|
TextView mProcessesHeader;
|
|
final ArrayList<ActiveDetail> mActiveDetails = new ArrayList<ActiveDetail>();
|
|
|
|
class ActiveDetail implements View.OnClickListener {
|
|
View mRootView;
|
|
Button mStopButton;
|
|
Button mReportButton;
|
|
RunningState.ServiceItem mServiceItem;
|
|
RunningProcessesView.ActiveItem mActiveItem;
|
|
RunningProcessesView.ViewHolder mViewHolder;
|
|
PendingIntent mManageIntent;
|
|
ComponentName mInstaller;
|
|
|
|
void stopActiveService(boolean confirmed) {
|
|
RunningState.ServiceItem si = mServiceItem;
|
|
if (!confirmed) {
|
|
if ((si.mServiceInfo.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
|
|
showConfirmStopDialog(si.mRunningService.service);
|
|
return;
|
|
}
|
|
}
|
|
getActivity().stopService(new Intent().setComponent(si.mRunningService.service));
|
|
if (mMergedItem == null) {
|
|
// If this is gone, we are gone.
|
|
mState.updateNow();
|
|
finish();
|
|
} else if (!mShowBackground && mMergedItem.mServices.size() <= 1) {
|
|
// If there was only one service, we are finishing it,
|
|
// so no reason for the UI to stick around.
|
|
mState.updateNow();
|
|
finish();
|
|
} else {
|
|
mState.updateNow();
|
|
}
|
|
}
|
|
|
|
public void onClick(View v) {
|
|
if (v == mReportButton) {
|
|
ApplicationErrorReport report = new ApplicationErrorReport();
|
|
report.type = ApplicationErrorReport.TYPE_RUNNING_SERVICE;
|
|
report.packageName = mServiceItem.mServiceInfo.packageName;
|
|
report.installerPackageName = mInstaller.getPackageName();
|
|
report.processName = mServiceItem.mRunningService.process;
|
|
report.time = System.currentTimeMillis();
|
|
report.systemApp = (mServiceItem.mServiceInfo.applicationInfo.flags
|
|
& ApplicationInfo.FLAG_SYSTEM) != 0;
|
|
ApplicationErrorReport.RunningServiceInfo info
|
|
= new ApplicationErrorReport.RunningServiceInfo();
|
|
if (mActiveItem.mFirstRunTime >= 0) {
|
|
info.durationMillis = SystemClock.elapsedRealtime()-mActiveItem.mFirstRunTime;
|
|
} else {
|
|
info.durationMillis = -1;
|
|
}
|
|
ComponentName comp = new ComponentName(mServiceItem.mServiceInfo.packageName,
|
|
mServiceItem.mServiceInfo.name);
|
|
File filename = getActivity().getFileStreamPath("service_dump.txt");
|
|
FileOutputStream output = null;
|
|
try {
|
|
output = new FileOutputStream(filename);
|
|
Debug.dumpService("activity", output.getFD(),
|
|
new String[] { "-a", "service", comp.flattenToString() });
|
|
} catch (IOException e) {
|
|
Log.w(TAG, "Can't dump service: " + comp, e);
|
|
} finally {
|
|
if (output != null) try { output.close(); } catch (IOException e) {}
|
|
}
|
|
FileInputStream input = null;
|
|
try {
|
|
input = new FileInputStream(filename);
|
|
byte[] buffer = new byte[(int) filename.length()];
|
|
input.read(buffer);
|
|
info.serviceDetails = new String(buffer);
|
|
} catch (IOException e) {
|
|
Log.w(TAG, "Can't read service dump: " + comp, e);
|
|
} finally {
|
|
if (input != null) try { input.close(); } catch (IOException e) {}
|
|
}
|
|
filename.delete();
|
|
Log.i(TAG, "Details: " + info.serviceDetails);
|
|
report.runningServiceInfo = info;
|
|
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);
|
|
return;
|
|
}
|
|
|
|
if (mManageIntent != null) {
|
|
try {
|
|
getActivity().startIntentSender(mManageIntent.getIntentSender(), null,
|
|
Intent.FLAG_ACTIVITY_NEW_TASK
|
|
| Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,
|
|
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET, 0);
|
|
} catch (IntentSender.SendIntentException e) {
|
|
Log.w(TAG, e);
|
|
} catch (IllegalArgumentException e) {
|
|
Log.w(TAG, e);
|
|
} catch (ActivityNotFoundException e) {
|
|
Log.w(TAG, e);
|
|
}
|
|
} else if (mServiceItem != null) {
|
|
stopActiveService(false);
|
|
} else if (mActiveItem.mItem.mBackground) {
|
|
// Background process. Just kill it.
|
|
mAm.killBackgroundProcesses(mActiveItem.mItem.mPackageInfo.packageName);
|
|
finish();
|
|
} else {
|
|
// Heavy-weight process. We'll do a force-stop on it.
|
|
mAm.forceStopPackage(mActiveItem.mItem.mPackageInfo.packageName);
|
|
finish();
|
|
}
|
|
}
|
|
}
|
|
|
|
StringBuilder mBuilder = new StringBuilder(128);
|
|
|
|
boolean findMergedItem() {
|
|
RunningState.MergedItem item = null;
|
|
ArrayList<RunningState.MergedItem> newItems = mShowBackground
|
|
? mState.getCurrentBackgroundItems() : mState.getCurrentMergedItems();
|
|
if (newItems != null) {
|
|
for (int i=0; i<newItems.size(); i++) {
|
|
RunningState.MergedItem mi = newItems.get(i);
|
|
if (mi.mUserId != mUserId) {
|
|
continue;
|
|
}
|
|
if (mUid >= 0 && mi.mProcess != null && mi.mProcess.mUid != mUid) {
|
|
continue;
|
|
}
|
|
if (mProcessName == null || (mi.mProcess != null
|
|
&& mProcessName.equals(mi.mProcess.mProcessName))) {
|
|
item = mi;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mMergedItem != item) {
|
|
mMergedItem = item;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void addServicesHeader() {
|
|
if (mNumServices == 0) {
|
|
mServicesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
|
|
mAllDetails, false);
|
|
mServicesHeader.setText(R.string.runningservicedetails_services_title);
|
|
mAllDetails.addView(mServicesHeader);
|
|
}
|
|
mNumServices++;
|
|
}
|
|
|
|
void addProcessesHeader() {
|
|
if (mNumProcesses == 0) {
|
|
mProcessesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
|
|
mAllDetails, false);
|
|
mProcessesHeader.setText(R.string.runningservicedetails_processes_title);
|
|
mAllDetails.addView(mProcessesHeader);
|
|
}
|
|
mNumProcesses++;
|
|
}
|
|
|
|
void addServiceDetailsView(RunningState.ServiceItem si, RunningState.MergedItem mi,
|
|
boolean isService, boolean inclDetails) {
|
|
if (isService) {
|
|
addServicesHeader();
|
|
} else if (mi.mUserId != UserHandle.myUserId()) {
|
|
// This is being called for another user, and is not a service...
|
|
// That is, it is a background processes, being added for the
|
|
// details of a user. In this case we want a header for processes,
|
|
// since the top subject line is for the user.
|
|
addProcessesHeader();
|
|
}
|
|
|
|
RunningState.BaseItem bi = si != null ? si : mi;
|
|
|
|
ActiveDetail detail = new ActiveDetail();
|
|
View root = mInflater.inflate(R.layout.running_service_details_service,
|
|
mAllDetails, false);
|
|
mAllDetails.addView(root);
|
|
detail.mRootView = root;
|
|
detail.mServiceItem = si;
|
|
detail.mViewHolder = new RunningProcessesView.ViewHolder(root);
|
|
detail.mActiveItem = detail.mViewHolder.bind(mState, bi, mBuilder);
|
|
|
|
if (!inclDetails) {
|
|
root.findViewById(R.id.service).setVisibility(View.GONE);
|
|
}
|
|
|
|
if (si != null && si.mRunningService.clientLabel != 0) {
|
|
detail.mManageIntent = mAm.getRunningServiceControlPanel(
|
|
si.mRunningService.service);
|
|
}
|
|
|
|
TextView description = (TextView)root.findViewById(R.id.comp_description);
|
|
detail.mStopButton = (Button)root.findViewById(R.id.left_button);
|
|
detail.mReportButton = (Button)root.findViewById(R.id.right_button);
|
|
|
|
if (isService && mi.mUserId != UserHandle.myUserId()) {
|
|
// For services from other users, we don't show any description or
|
|
// controls, because the current user can not perform
|
|
// actions on them.
|
|
description.setVisibility(View.GONE);
|
|
root.findViewById(R.id.control_buttons_panel).setVisibility(View.GONE);
|
|
} else {
|
|
if (si != null && si.mServiceInfo.descriptionRes != 0) {
|
|
description.setText(getActivity().getPackageManager().getText(
|
|
si.mServiceInfo.packageName, si.mServiceInfo.descriptionRes,
|
|
si.mServiceInfo.applicationInfo));
|
|
} else {
|
|
if (mi.mBackground) {
|
|
description.setText(R.string.background_process_stop_description);
|
|
} else if (detail.mManageIntent != null) {
|
|
try {
|
|
Resources clientr = getActivity().getPackageManager().getResourcesForApplication(
|
|
si.mRunningService.clientPackage);
|
|
String label = clientr.getString(si.mRunningService.clientLabel);
|
|
description.setText(getActivity().getString(R.string.service_manage_description,
|
|
label));
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
}
|
|
} else {
|
|
description.setText(getActivity().getText(si != null
|
|
? R.string.service_stop_description
|
|
: R.string.heavy_weight_stop_description));
|
|
}
|
|
}
|
|
|
|
detail.mStopButton.setOnClickListener(detail);
|
|
detail.mStopButton.setText(getActivity().getText(detail.mManageIntent != null
|
|
? R.string.service_manage : R.string.service_stop));
|
|
detail.mReportButton.setOnClickListener(detail);
|
|
detail.mReportButton.setText(com.android.internal.R.string.report);
|
|
// check if error reporting is enabled in secure settings
|
|
int enabled = Settings.Global.getInt(getActivity().getContentResolver(),
|
|
Settings.Global.SEND_ACTION_APP_ERROR, 0);
|
|
if (enabled != 0 && si != null) {
|
|
detail.mInstaller = ApplicationErrorReport.getErrorReportReceiver(
|
|
getActivity(), si.mServiceInfo.packageName,
|
|
si.mServiceInfo.applicationInfo.flags);
|
|
detail.mReportButton.setEnabled(detail.mInstaller != null);
|
|
} else {
|
|
detail.mReportButton.setEnabled(false);
|
|
}
|
|
}
|
|
|
|
mActiveDetails.add(detail);
|
|
}
|
|
|
|
void addProcessDetailsView(RunningState.ProcessItem pi, boolean isMain) {
|
|
addProcessesHeader();
|
|
|
|
ActiveDetail detail = new ActiveDetail();
|
|
View root = mInflater.inflate(R.layout.running_service_details_process,
|
|
mAllDetails, false);
|
|
mAllDetails.addView(root);
|
|
detail.mRootView = root;
|
|
detail.mViewHolder = new RunningProcessesView.ViewHolder(root);
|
|
detail.mActiveItem = detail.mViewHolder.bind(mState, pi, mBuilder);
|
|
|
|
TextView description = (TextView)root.findViewById(R.id.comp_description);
|
|
if (pi.mUserId != UserHandle.myUserId()) {
|
|
// Processes for another user are all shown batched together; there is
|
|
// no reason to have a description.
|
|
description.setVisibility(View.GONE);
|
|
} else if (isMain) {
|
|
description.setText(R.string.main_running_process_description);
|
|
} else {
|
|
int textid = 0;
|
|
CharSequence label = null;
|
|
ActivityManager.RunningAppProcessInfo rpi = pi.mRunningProcessInfo;
|
|
final ComponentName comp = rpi.importanceReasonComponent;
|
|
//Log.i(TAG, "Secondary proc: code=" + rpi.importanceReasonCode
|
|
// + " pid=" + rpi.importanceReasonPid + " comp=" + comp);
|
|
switch (rpi.importanceReasonCode) {
|
|
case ActivityManager.RunningAppProcessInfo.REASON_PROVIDER_IN_USE:
|
|
textid = R.string.process_provider_in_use_description;
|
|
if (rpi.importanceReasonComponent != null) {
|
|
try {
|
|
ProviderInfo prov = getActivity().getPackageManager().getProviderInfo(
|
|
rpi.importanceReasonComponent, 0);
|
|
label = RunningState.makeLabel(getActivity().getPackageManager(),
|
|
prov.name, prov);
|
|
} catch (NameNotFoundException e) {
|
|
}
|
|
}
|
|
break;
|
|
case ActivityManager.RunningAppProcessInfo.REASON_SERVICE_IN_USE:
|
|
textid = R.string.process_service_in_use_description;
|
|
if (rpi.importanceReasonComponent != null) {
|
|
try {
|
|
ServiceInfo serv = getActivity().getPackageManager().getServiceInfo(
|
|
rpi.importanceReasonComponent, 0);
|
|
label = RunningState.makeLabel(getActivity().getPackageManager(),
|
|
serv.name, serv);
|
|
} catch (NameNotFoundException e) {
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (textid != 0 && label != null) {
|
|
description.setText(getActivity().getString(textid, label));
|
|
}
|
|
}
|
|
|
|
mActiveDetails.add(detail);
|
|
}
|
|
|
|
void addDetailsViews(RunningState.MergedItem item, boolean inclServices,
|
|
boolean inclProcesses) {
|
|
if (item != null) {
|
|
if (inclServices) {
|
|
for (int i=0; i<item.mServices.size(); i++) {
|
|
addServiceDetailsView(item.mServices.get(i), item, true, true);
|
|
}
|
|
}
|
|
|
|
if (inclProcesses) {
|
|
if (item.mServices.size() <= 0) {
|
|
// This item does not have any services, so it must be
|
|
// another interesting process... we will put a fake service
|
|
// entry for it, to allow the user to "stop" it.
|
|
addServiceDetailsView(null, item, false, item.mUserId != UserHandle.myUserId());
|
|
} else {
|
|
// This screen is actually showing services, so also show
|
|
// the process details.
|
|
for (int i=-1; i<item.mOtherProcesses.size(); i++) {
|
|
RunningState.ProcessItem pi = i < 0 ? item.mProcess
|
|
: item.mOtherProcesses.get(i);
|
|
if (pi != null && pi.mPid <= 0) {
|
|
continue;
|
|
}
|
|
|
|
addProcessDetailsView(pi, i < 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void addDetailViews() {
|
|
for (int i=mActiveDetails.size()-1; i>=0; i--) {
|
|
mAllDetails.removeView(mActiveDetails.get(i).mRootView);
|
|
}
|
|
mActiveDetails.clear();
|
|
|
|
if (mServicesHeader != null) {
|
|
mAllDetails.removeView(mServicesHeader);
|
|
mServicesHeader = null;
|
|
}
|
|
|
|
if (mProcessesHeader != null) {
|
|
mAllDetails.removeView(mProcessesHeader);
|
|
mProcessesHeader = null;
|
|
}
|
|
|
|
mNumServices = mNumProcesses = 0;
|
|
|
|
if (mMergedItem != null) {
|
|
if (mMergedItem.mUser != null) {
|
|
ArrayList<RunningState.MergedItem> items;
|
|
if (mShowBackground) {
|
|
items = new ArrayList<RunningState.MergedItem>(mMergedItem.mChildren);
|
|
Collections.sort(items, mState.mBackgroundComparator);
|
|
} else {
|
|
items = mMergedItem.mChildren;
|
|
}
|
|
for (int i=0; i<items.size(); i++) {
|
|
addDetailsViews(items.get(i), true, false);
|
|
}
|
|
for (int i=0; i<items.size(); i++) {
|
|
addDetailsViews(items.get(i), false, true);
|
|
}
|
|
} else {
|
|
addDetailsViews(mMergedItem, true, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void refreshUi(boolean dataChanged) {
|
|
if (findMergedItem()) {
|
|
dataChanged = true;
|
|
}
|
|
if (dataChanged) {
|
|
if (mMergedItem != null) {
|
|
mSnippetActiveItem = mSnippetViewHolder.bind(mState,
|
|
mMergedItem, mBuilder);
|
|
} else if (mSnippetActiveItem != null) {
|
|
// Clear whatever is currently being shown.
|
|
mSnippetActiveItem.mHolder.size.setText("");
|
|
mSnippetActiveItem.mHolder.uptime.setText("");
|
|
mSnippetActiveItem.mHolder.description.setText(R.string.no_services);
|
|
} else {
|
|
// No merged item, never had one. Nothing to do.
|
|
finish();
|
|
return;
|
|
}
|
|
addDetailViews();
|
|
}
|
|
}
|
|
|
|
private void finish() {
|
|
ThreadUtils.postOnMainThread(() -> {
|
|
final Activity a = getActivity();
|
|
if (a != null) {
|
|
a.onBackPressed();
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
setHasOptionsMenu(true);
|
|
mUid = getArguments().getInt(KEY_UID, -1);
|
|
mUserId = getArguments().getInt(KEY_USER_ID, 0);
|
|
mProcessName = getArguments().getString(KEY_PROCESS, null);
|
|
mShowBackground = getArguments().getBoolean(KEY_BACKGROUND, false);
|
|
|
|
mAm = (ActivityManager) getActivity().getSystemService(Context.ACTIVITY_SERVICE);
|
|
mInflater = (LayoutInflater) getActivity().getSystemService(
|
|
Context.LAYOUT_INFLATER_SERVICE);
|
|
|
|
mState = RunningState.getInstance(getActivity());
|
|
}
|
|
|
|
@Override
|
|
public View onCreateView(
|
|
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
final View view = inflater.inflate(R.layout.running_service_details, container, false);
|
|
Utils.prepareCustomPreferencesList(container, view, view, false);
|
|
|
|
mRootView = view;
|
|
mAllDetails = (ViewGroup)view.findViewById(R.id.all_details);
|
|
mSnippet = (ViewGroup)view.findViewById(R.id.snippet);
|
|
mSnippetViewHolder = new RunningProcessesView.ViewHolder(mSnippet);
|
|
|
|
// We want to retrieve the data right now, so any active managed
|
|
// dialog that gets created can find it.
|
|
ensureData();
|
|
|
|
return view;
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
super.onPause();
|
|
mHaveData = false;
|
|
mState.pause();
|
|
}
|
|
|
|
@Override
|
|
public int getMetricsCategory() {
|
|
return MetricsEvent.RUNNING_SERVICE_DETAILS;
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
super.onResume();
|
|
ensureData();
|
|
}
|
|
|
|
ActiveDetail activeDetailForService(ComponentName comp) {
|
|
for (int i=0; i<mActiveDetails.size(); i++) {
|
|
ActiveDetail ad = mActiveDetails.get(i);
|
|
if (ad.mServiceItem != null && ad.mServiceItem.mRunningService != null
|
|
&& comp.equals(ad.mServiceItem.mRunningService.service)) {
|
|
return ad;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void showConfirmStopDialog(ComponentName comp) {
|
|
DialogFragment newFragment = MyAlertDialogFragment.newConfirmStop(
|
|
DIALOG_CONFIRM_STOP, comp);
|
|
newFragment.setTargetFragment(this, 0);
|
|
newFragment.show(getFragmentManager(), "confirmstop");
|
|
}
|
|
|
|
public static class MyAlertDialogFragment extends InstrumentedDialogFragment {
|
|
|
|
public static MyAlertDialogFragment newConfirmStop(int id, ComponentName comp) {
|
|
MyAlertDialogFragment frag = new MyAlertDialogFragment();
|
|
Bundle args = new Bundle();
|
|
args.putInt("id", id);
|
|
args.putParcelable("comp", comp);
|
|
frag.setArguments(args);
|
|
return frag;
|
|
}
|
|
|
|
RunningServiceDetails getOwner() {
|
|
return (RunningServiceDetails)getTargetFragment();
|
|
}
|
|
|
|
@Override
|
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
int id = getArguments().getInt("id");
|
|
switch (id) {
|
|
case DIALOG_CONFIRM_STOP: {
|
|
final ComponentName comp = (ComponentName)getArguments().getParcelable("comp");
|
|
if (getOwner().activeDetailForService(comp) == null) {
|
|
return null;
|
|
}
|
|
|
|
return new AlertDialog.Builder(getActivity())
|
|
.setTitle(getActivity().getString(R.string.runningservicedetails_stop_dlg_title))
|
|
.setMessage(getActivity().getString(R.string.runningservicedetails_stop_dlg_text))
|
|
.setPositiveButton(R.string.dlg_ok,
|
|
new DialogInterface.OnClickListener() {
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
ActiveDetail ad = getOwner().activeDetailForService(comp);
|
|
if (ad != null) {
|
|
ad.stopActiveService(true);
|
|
}
|
|
}
|
|
})
|
|
.setNegativeButton(R.string.dlg_cancel, null)
|
|
.create();
|
|
}
|
|
}
|
|
throw new IllegalArgumentException("unknown id " + id);
|
|
}
|
|
|
|
@Override
|
|
public int getMetricsCategory() {
|
|
return MetricsEvent.DIALOG_RUNNIGN_SERVICE;
|
|
}
|
|
}
|
|
|
|
void ensureData() {
|
|
if (!mHaveData) {
|
|
mHaveData = true;
|
|
mState.resume(this);
|
|
|
|
// We want to go away if the service being shown no longer exists,
|
|
// so we need to ensure we have done the initial data retrieval before
|
|
// showing our ui.
|
|
mState.waitForData();
|
|
|
|
// And since we know we have the data, let's show the UI right away
|
|
// to avoid flicker.
|
|
refreshUi(true);
|
|
}
|
|
}
|
|
|
|
void updateTimes() {
|
|
if (mSnippetActiveItem != null) {
|
|
mSnippetActiveItem.updateTime(getActivity(), mBuilder);
|
|
}
|
|
for (int i=0; i<mActiveDetails.size(); i++) {
|
|
mActiveDetails.get(i).mActiveItem.updateTime(getActivity(), mBuilder);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onRefreshUi(int what) {
|
|
if (getActivity() == null) return;
|
|
switch (what) {
|
|
case REFRESH_TIME:
|
|
updateTimes();
|
|
break;
|
|
case REFRESH_DATA:
|
|
refreshUi(false);
|
|
updateTimes();
|
|
break;
|
|
case REFRESH_STRUCTURE:
|
|
refreshUi(true);
|
|
updateTimes();
|
|
break;
|
|
}
|
|
}
|
|
}
|