Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 271c8b06 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Make manage apps UI multi-user aware.

The details screens still need some work.

Change-Id: I850cc9ba9a8db7787fae629ae3cb6c6772c726f5
parent e54660d8
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -56,6 +56,9 @@
    <uses-permission android:name="android.permission.MANAGE_USB" />
    <uses-permission android:name="android.permission.SET_POINTER_SPEED" />
    <uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
    <uses-permission android:name="android.permission.COPY_PROTECTED_DATA" />
    <uses-permission android:name="android.permission.MANAGE_USERS" />

    <application android:label="@string/settings_label"
            android:icon="@mipmap/ic_launcher_settings"
+2 −0
Original line number Diff line number Diff line
@@ -2626,6 +2626,8 @@
    <string name="memory">RAM</string>
    <!-- Text to label a process entry with the process name. -->
    <string name="service_process_name"><xliff:g id="process">%1$s</xliff:g></string>
    <!-- [CHAR LIMIT=NONE] Label of a running process that represents another user -->
    <string name="running_process_item_user_label">User: <xliff:g id="user_name">%1$s</xliff:g></string>
    <!-- Descriptive text of a running process: singular process, singular service. -->
    <string name="running_processes_item_description_s_s"><xliff:g id="numprocess">%1$d</xliff:g>
        process and <xliff:g id="numservices">%2$d</xliff:g> service</string>
+1 −0
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ public class Settings extends PreferenceActivity
            R.id.device_section,
            R.id.sound_settings,
            R.id.display_settings,
            R.id.application_settings,
            R.id.personal_section,
            R.id.security_settings,
            R.id.account_settings,
+32 −15
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.UserHandle;
import android.preference.PreferenceActivity;
import android.text.format.DateUtils;
import android.text.format.Formatter;
@@ -42,6 +43,7 @@ import android.widget.TextView;
import android.widget.AbsListView.RecyclerListener;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;

@@ -49,6 +51,8 @@ public class RunningProcessesView extends FrameLayout
        implements AdapterView.OnItemClickListener, RecyclerListener,
        RunningState.OnRefreshUiListener {
    
    final int mMyUserId;

    long SECONDARY_SERVER_MEM;
    
    final HashMap<View, ActiveItem> mActiveItems = new HashMap<View, ActiveItem>();
@@ -167,10 +171,13 @@ public class RunningProcessesView extends FrameLayout
                if (item.mPackageInfo == null && item instanceof RunningState.MergedItem) {
                    // Items for background processes don't normally load
                    // their labels for performance reasons.  Do it now.
                    RunningState.MergedItem mergedItem = (RunningState.MergedItem)item;
                    if (mergedItem.mProcess != null) {
                        ((RunningState.MergedItem)item).mProcess.ensureLabel(pm);
                        item.mPackageInfo = ((RunningState.MergedItem)item).mProcess.mPackageInfo;
                        item.mDisplayLabel = ((RunningState.MergedItem)item).mProcess.mDisplayLabel;
                    }
                }
                name.setText(item.mDisplayLabel);
                ActiveItem ai = new ActiveItem();
                ai.mRootView = rootView;
@@ -183,9 +190,7 @@ public class RunningProcessesView extends FrameLayout
                    description.setText(item.mDescription);
                }
                item.mCurSizeStr = null;
                if (item.mPackageInfo != null) {
                    icon.setImageDrawable(item.mPackageInfo.loadIcon(pm));
                }
                icon.setImageDrawable(item.loadIcon(rootView.getContext(), state));
                icon.setVisibility(View.VISIBLE);
                ai.updateTime(rootView.getContext(), builder);
                return ai;
@@ -203,7 +208,9 @@ public class RunningProcessesView extends FrameLayout
        final RunningState mState;
        final LayoutInflater mInflater;
        boolean mShowBackground;
        ArrayList<RunningState.MergedItem> mItems;
        ArrayList<RunningState.MergedItem> mOrigItems;
        final ArrayList<RunningState.MergedItem> mItems
                = new ArrayList<RunningState.MergedItem>();
        
        ServiceListAdapter(RunningState state) {
            mState = state;
@@ -230,11 +237,17 @@ public class RunningProcessesView extends FrameLayout
            ArrayList<RunningState.MergedItem> newItems =
                mShowBackground ? mState.getCurrentBackgroundItems()
                        : mState.getCurrentMergedItems();
            if (mItems != newItems) {
                mItems = newItems;
            if (mOrigItems != newItems) {
                mOrigItems = newItems;
                if (newItems == null) {
                    mItems.clear();
                } else {
                    mItems.clear();
                    mItems.addAll(newItems);
                    if (mShowBackground) {
                        Collections.sort(mItems, mState.mBackgroundComparator);
                    }
                }
            if (mItems == null) {
                mItems = new ArrayList<RunningState.MergedItem>();
            }
        }
        
@@ -374,8 +387,11 @@ public class RunningProcessesView extends FrameLayout
        if (mOwner != null) {
            // start new fragment to display extended information
            Bundle args = new Bundle();
            if (mi.mProcess != null) {
                args.putInt(RunningServiceDetails.KEY_UID, mi.mProcess.mUid);
                args.putString(RunningServiceDetails.KEY_PROCESS, mi.mProcess.mProcessName);
            }
            args.putInt(RunningServiceDetails.KEY_USER_ID, mi.mUserId);
            args.putBoolean(RunningServiceDetails.KEY_BACKGROUND, mAdapter.mShowBackground);
    
            PreferenceActivity pa = (PreferenceActivity)mOwner.getActivity();
@@ -390,6 +406,7 @@ public class RunningProcessesView extends FrameLayout

    public RunningProcessesView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mMyUserId = UserHandle.myUserId();
    }
    
    public void doCreate(Bundle savedInstanceState) {
+154 −83
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
@@ -39,12 +40,14 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;

public class RunningServiceDetails extends Fragment
        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";

@@ -57,6 +60,7 @@ public class RunningServiceDetails extends Fragment
    boolean mHaveData;

    int mUid;
    int mUserId;
    String mProcessName;
    boolean mShowBackground;

@@ -195,8 +199,14 @@ public class RunningServiceDetails extends Fragment
        if (newItems != null) {
            for (int i=0; i<newItems.size(); i++) {
                RunningState.MergedItem mi = newItems.get(i);
                if (mi.mProcess.mUid == mUid
                        && mi.mProcess.mProcessName.equals(mProcessName)) {
                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;
                }
@@ -210,7 +220,7 @@ public class RunningServiceDetails extends Fragment
        return false;
    }

    void addServiceDetailsView(RunningState.ServiceItem si, RunningState.MergedItem mi) {
    void addServicesHeader() {
        if (mNumServices == 0) {
            mServicesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
                    mAllDetails, false);
@@ -218,6 +228,29 @@ public class RunningServiceDetails extends Fragment
            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;
        
@@ -230,12 +263,26 @@ public class RunningServiceDetails extends Fragment
        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,
@@ -259,12 +306,9 @@ public class RunningServiceDetails extends Fragment
                }
            }

        detail.mStopButton = (Button)root.findViewById(R.id.left_button);
            detail.mStopButton.setOnClickListener(detail);
            detail.mStopButton.setText(getActivity().getText(detail.mManageIntent != null
                    ? R.string.service_manage : R.string.service_stop));

        detail.mReportButton = (Button)root.findViewById(R.id.right_button);
            detail.mReportButton.setOnClickListener(detail);
            detail.mReportButton.setText(com.android.internal.R.string.report);
            // check if error reporting is enabled in secure settings
@@ -278,18 +322,13 @@ public class RunningServiceDetails extends Fragment
            } else {
                detail.mReportButton.setEnabled(false);
            }
        }

        mActiveDetails.add(detail);
    }

    void addProcessDetailsView(RunningState.ProcessItem pi, boolean isMain) {
        if (mNumProcesses == 0) {
            mProcessesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
                    mAllDetails, false);
            mProcessesHeader.setText(R.string.runningservicedetails_processes_title);
            mAllDetails.addView(mProcessesHeader);
        }
        mNumProcesses++;
        addProcessesHeader();

        ActiveDetail detail = new ActiveDetail();
        View root = mInflater.inflate(R.layout.running_service_details_process,
@@ -300,7 +339,11 @@ public class RunningServiceDetails extends Fragment
        detail.mActiveItem = detail.mViewHolder.bind(mState, pi, mBuilder);
        
        TextView description = (TextView)root.findViewById(R.id.comp_description);
        if (isMain) {
        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;
@@ -343,6 +386,38 @@ public class RunningServiceDetails extends Fragment
        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);
@@ -361,27 +436,22 @@ public class RunningServiceDetails extends Fragment

        mNumServices = mNumProcesses = 0;

        if (mMergedItem != null) {
            for (int i=0; i<mMergedItem.mServices.size(); i++) {
                addServiceDetailsView(mMergedItem.mServices.get(i), mMergedItem);
            }
            
            if (mMergedItem.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, mMergedItem);
        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=-1; i<mMergedItem.mOtherProcesses.size(); i++) {
                RunningState.ProcessItem pi = i < 0 ? mMergedItem.mProcess
                        : mMergedItem.mOtherProcesses.get(i);
                if (pi.mPid <= 0) {
                    continue;
            for (int i=0; i<items.size(); i++) {
                addDetailsViews(items.get(i), true, false);
            }
                
                addProcessDetailsView(pi, i < 0);
            for (int i=0; i<items.size(); i++) {
                addDetailsViews(items.get(i), false, true);
            }
        } else {
            addDetailsViews(mMergedItem, true, true);
        }
    }
    
@@ -423,8 +493,9 @@ public class RunningServiceDetails extends Fragment
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        mUid = getArguments().getInt(KEY_UID, 0);
        mProcessName = getArguments().getString(KEY_PROCESS);
        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);
Loading