Wednesday, December 9, 2015

android - How to get running processes

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity"
    android:background="#005eff"
    >
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
    <Button
        android:id="@+id/btn_refresh"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Refresh"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:background="#90b990"
        />
    <Button
        android:id="@+id/btn_kill"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Kill"
        android:layout_above="@id/btn_refresh"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:background="#789f7b"
        />
</RelativeLayout>
custom_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    card_view:cardCornerRadius="4dp"
    card_view:contentPadding="5dp"
    android:clickable="false"
   >
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#cbd7f1"
        android:layout_margin="2dp"
        android:padding="5dp"
        android:clickable="false"
        >
        <TextView
            android:id="@+id/tv_process_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:clickable="false"
            />
        <TextView
            android:id="@+id/tv_package_list"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="25dp"
            android:paddingRight="25dp"
            android:clickable="false"
            />
    </LinearLayout>
</android.support.v7.widget.CardView>
MainActivity.java

package com.cfsuman.me.androidcode;

import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.Toast;
import java.util.List;


public class MainActivity extends AppCompatActivity {
    private Context mContext;

    private Button mButtonRefresh;
    private Button mButtonKill;
    private RecyclerView mRecyclerView;

    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Request window feature action bar
        requestWindowFeature(Window.FEATURE_ACTION_BAR);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Get the application context
        mContext = getApplicationContext();

        // Set the action bar color
        getSupportActionBar().setBackgroundDrawable(new ColorDrawable(Color.RED));

        // Get the widgets reference from XML layout
        mButtonRefresh = (Button) findViewById(R.id.btn_refresh);
        mButtonKill = (Button) findViewById(R.id.btn_kill);
        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);

        // Use a linear layout manager
        mLayoutManager = new LinearLayoutManager(mContext);
        mRecyclerView.setLayoutManager(mLayoutManager);

        // Specify an adapter for RecyclerView
        mAdapter = new RecyclerAdapter(getDataSet(),mContext);
        mRecyclerView.setAdapter(mAdapter);

        // Set a click listener for refresh button widget
        mButtonRefresh.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Regenerate the adapter for RecyclerView
                mAdapter = new RecyclerAdapter(getDataSet(),mContext);
                mRecyclerView.setAdapter(mAdapter);

                // Show the number of running processes
                Toast.makeText(mContext, "Running processes : "
                        + mAdapter.getItemCount(), Toast.LENGTH_SHORT).show();
            }
        });

        // Set a click listener for kill button widget
        mButtonKill.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Kill the background processes
                new KillBackgroundProcessesTask().execute();
            }
        });
    }

    // Custom method to generate data set
    protected ActivityManager.RunningAppProcessInfo[] getDataSet(){
        /*
            ActivityManager
                Interact with the overall activities running in the system.
        */
        ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
        /*
            public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses ()
                Returns a list of application processes that are running on the device.
                Note: this method is only intended for debugging or building a user-facing
                process management UI.

            Returns
                Returns a list of RunningAppProcessInfo records, or null if there are no running
                processes (it will not return an empty list). This list ordering is not specified.
        */
        List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfoList = am.getRunningAppProcesses();

        ActivityManager.RunningAppProcessInfo[] array = runningAppProcessInfoList.toArray(
                new ActivityManager.RunningAppProcessInfo[runningAppProcessInfoList.size()]
        );

        return array;
    }

    // AsyncTask to kill background processes
    private class KillBackgroundProcessesTask extends AsyncTask<Void,Integer,Integer>{
        @Override
        protected Integer doInBackground(Void...Void){
            // Get an instance of PackageManager
            PackageManager pm = getPackageManager();

            // Get an instance of ActivityManager
            ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);

            // Get a list of RunningAppProcessInfo
            List<ActivityManager.RunningAppProcessInfo> list = am.getRunningAppProcesses();

            // Count the number of running processes
            int initialRunningProcessesSize = list.size();

            // Iterate over the RunningAppProcess list
            for(ActivityManager.RunningAppProcessInfo process: list){
                // Ignore, if the process contains package list is empty
                if(process.pkgList.length == 0) continue;

                try{
                    // Get the PackageInfo for current process
                    PackageInfo packageInfo = pm.getPackageInfo(process.pkgList[0],PackageManager.GET_ACTIVITIES);

                    // Ignore the self app package
                    if(!packageInfo.packageName.equals(mContext.getPackageName())){
                        // Try to kill other background processes
                        // System processes are ignored
                        am.killBackgroundProcesses(packageInfo.packageName);
                    }
                }catch(PackageManager.NameNotFoundException e){
                    // Catch the exception
                    e.printStackTrace();
                }
            }

            // Get the running processes after killing some
            int currentRunningProcessesSize = am.getRunningAppProcesses().size();

            // Return the number of killed processes
            return initialRunningProcessesSize - currentRunningProcessesSize;
        }

        protected void onPostExecute(Integer result){
            // Show the number of killed processes
            Toast.makeText(mContext,"Killed : " + result + " processes",Toast.LENGTH_SHORT).show();
        }
    }
}
RecyclerAdapter.java

package com.cfsuman.me.androidcode;


import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;


public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
    private ActivityManager.RunningAppProcessInfo[] mDataset;
    private Context mContext;

    // Provide a reference to the views for each data item
    public static class ViewHolder extends RecyclerView.ViewHolder{
        public TextView mTVProcessName;
        public TextView mTVPackageList;
        public ViewHolder(View v){
            super(v);
            mTVProcessName = (TextView) v.findViewById(R.id.tv_process_name);
            mTVPackageList = (TextView) v.findViewById(R.id.tv_package_list);
        }
    }

    // Provide a suitable constructor
    public RecyclerAdapter(ActivityManager.RunningAppProcessInfo[] myDataset,Context context){
        mDataset = myDataset;
        mContext = context;
    }

    // Create new views
    @Override
    public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
        // Create a new view
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_layout,parent,false);
        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder holder, int position){
        // Get element from data set at this position
        // Replace the contents of the view with that element
        String processString = "<b><u>"+mDataset[position].processName + "</u></b> ";

        processString += "<i>(" + getProcessImportance(mDataset[position].importance).toLowerCase()+")</i>";
        holder.mTVProcessName.setText(Html.fromHtml(processString));

        // By default android takes the package name as the process name.
        holder.mTVPackageList.setText("");
        String[] packages = mDataset[position].pkgList;

        StringBuilder builder = new StringBuilder();
        for (int i=0;i<packages.length;i++){
            // Get the application name
            builder.append("<b>" + getApplicationName(packages[i])+"</b><br/>");

            // Determine is it a system application or not
            if(isSystemApplication(packages[i])){
                builder.append("<i>System app.</i><br/>");
            }

            // Append the package name
            builder.append(packages[i] + "<br/>");

            // Show the formatted string in CardView
            holder.mTVPackageList.setText(Html.fromHtml(builder.toString()));
        }
    }

    // Return the size of data set
    @Override
    public int getItemCount(){
        return mDataset.length;
    }

    // Custom method to get process importance
    protected String getProcessImportance(int importance){
        String processImportance = "";
        /*
            The relative importance level that the system places on this process. May be one of
                IMPORTANCE_FOREGROUND,
                IMPORTANCE_VISIBLE,
                IMPORTANCE_SERVICE,
                IMPORTANCE_BACKGROUND,
                IMPORTANCE_EMPTY.

            These constants are numbered so that "more important" values are always smaller
            than "less important" values.
        */
        if(importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND){
            processImportance = "BACKGROUND";
        }else if (importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY){
            processImportance = "EMPTY";
        }else if(importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
            processImportance = "FOREGROUND";

        }else if (importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE){
            processImportance = "FOREGROUND SERVICE";
        }else if (importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE){
            processImportance = "GONE";
        }else if (importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE){
            processImportance = "PERCEPTIBLE";
        }else if(importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE){
            processImportance = "SERVICE";
        }else if(importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_TOP_SLEEPING){
            processImportance = "TOP SLEEPING";
        }else if(importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE){
            processImportance = "VISIBLE";
        }

        return processImportance;
    }

    // Custom method to get application label from package name
    protected String getApplicationName(String packageName){
        String applicationName = "";
        PackageManager pm = mContext.getPackageManager();
        ApplicationInfo ai;
        try{
            ai = pm.getApplicationInfo(packageName,0);
        }catch(PackageManager.NameNotFoundException e){
            e.printStackTrace();;
            ai = null;
        }

        applicationName = (String)(ai!=null ? pm.getApplicationLabel(ai) : "(UNKNOWN)");
        return  applicationName;
    }

    // Custom method to determine an application (package) is system package
    protected boolean isSystemApplication(String packageName){
        boolean isSystemApp = false;
        PackageManager pm = mContext.getPackageManager();
        ApplicationInfo ai;
        try{
            ai = pm.getApplicationInfo(packageName,0);
        }catch(PackageManager.NameNotFoundException e){
            e.printStackTrace();;
            ai = null;
        }

        if(ai!=null & ai.flags == ApplicationInfo.FLAG_SYSTEM){
            isSystemApp = true;
        }

        return  isSystemApp;
    }
}
AndroidManifes.xml [permission]

<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
build.gradle [dependencies]

compile 'com.android.support:recyclerview-v7:23.0.1'
compile 'com.android.support:cardview-v7:23.0.1'