[Android]  PackageManagerを用いた端末内アプリ一覧の取得とフィルタリングの実装メモ

PackageManagerを用いて、端末内にインストールされているアプリ情報を取得し、リスト表示したアプリ情報を検索条件によってフィルタリングするものを作ったので、メモしておきます。

#作ったもの
端末内のアプリ情報一覧をアプリの「評価」と「インストール数」でフィルタリングするものです。
「評価（星1~3）」と「インストール数(1000~3999)」は、各アプリに適当に設定しています。
評価の条件選択肢は、「指定なし」「星1」「星2」「星3」です。
インストール数の条件選択肢は、「指定なし」「1000~1999」「2000~2999」「3000~3999」です。

<img width="522" alt="スクリーンショット 2019-02-16 18.11.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/281645/beb10e9c-761d-2842-c178-bd68bdfbb274.png">
<img width="515" alt="スクリーンショット 2019-02-16 18.24.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/281645/1c47c79d-2345-5ae2-aed4-21a01556b008.png">
<img width="518" alt="スクリーンショット 2019-02-16 18.24.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/281645/c1a3a013-7dc9-a881-3237-a7505305ba3e.png">


#MainActivity.java
```java:MainActivity.java
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class MainActivity extends AppCompatActivity {

    PackageManager pm = null;

    ListView listView1;
    static List<MyAppInfo> dataList = new ArrayList<MyAppInfo>();
    static PackageListAdapter adapter = null;

    Button bt;
    Spinner spEval;
    Spinner spInstNum;

    String spEvalItem;
    String spInstNumItem;

    String[] selectEvals = new String[]{"指定なし", "星1", "星2", "星3"};
    String[] selectInstNum = new String[]{"指定なし", "1000~1999", "2000~2999", "3000~3999"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bt = (Button) findViewById(R.id.button);
        spEval = (Spinner) findViewById(R.id.spinner1);
        spInstNum = (Spinner) findViewById(R.id.spinner2);

        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                spEvalItem = (String) spEval.getSelectedItem();
                spInstNumItem = (String) spInstNum.getSelectedItem();

                updatePackageList(spEvalItem, spInstNumItem);

            }
        });

        pm = getApplicationContext().getPackageManager();

        listView1 = (ListView) findViewById(R.id.listView1);

        adapter = new PackageListAdapter();
        listView1.setAdapter(adapter);

        updatePackageList(selectEvals[0], selectInstNum[0]);
    }

    //アプリ一覧表示
    protected void updatePackageList(String selectEv, String selectIn){
        dataList.clear();
        List<PackageInfo> pkgInfoList = pm.getInstalledPackages(0);

        Random random = new Random();
        int i = 0;

        for(PackageInfo pkgInfo : pkgInfoList){
            ApplicationInfo appInfo = pkgInfo.applicationInfo;
            String sourceDir = appInfo.publicSourceDir;

            int installNum = random.nextInt(3000) + 1000;
            String eval;

            i++;

            //適当に評価、インストール数を設定
            if((i % 5) == 0){
                eval = selectEvals[1];
            }else if((i % 2) == 0){
                eval = selectEvals[2];
            }else {
                eval = selectEvals[3];
            }

            //フィルタリング条件分岐
            if(!sourceDir.startsWith("/system/") && selectEvals[0].equals(selectEv) && selectInstNum[0].equals(selectIn)){
                String label = appInfo.loadLabel(pm).toString();
                Drawable drawable = appInfo.loadIcon(pm);
                dataList.add(new MyAppInfo(sourceDir, label, drawable, eval, installNum));

            }else if(!sourceDir.startsWith("/system/") && eval.equals(selectEv) && selectInstNum[0].equals(selectIn)){
                String label = appInfo.loadLabel(pm).toString();
                Drawable drawable = appInfo.loadIcon(pm);
                dataList.add(new MyAppInfo(sourceDir, label, drawable, eval, installNum));

            }else if(!sourceDir.startsWith("/system/") && (eval.equals(selectEv) || selectEvals[0].equals(selectEv)) && selectInstNum[1].equals(selectIn)){
                if((1000 <= installNum) && (installNum <= 1999)) {
                    String label = appInfo.loadLabel(pm).toString();
                    Drawable drawable = appInfo.loadIcon(pm);
                    dataList.add(new MyAppInfo(sourceDir, label, drawable, eval, installNum));
                }

            }else if(!sourceDir.startsWith("/system/") && (eval.equals(selectEv) || selectEvals[0].equals(selectEv)) && selectInstNum[2].equals(selectIn)){
                if((2000 <= installNum) && (installNum <= 2999)) {
                    String label = appInfo.loadLabel(pm).toString();
                    Drawable drawable = appInfo.loadIcon(pm);
                    dataList.add(new MyAppInfo(sourceDir, label, drawable, eval, installNum));
                }

            }else if(!sourceDir.startsWith("/system/") && (eval.equals(selectEv) || selectEvals[0].equals(selectEv)) && selectInstNum[3].equals(selectIn)){
                if((3000 <= installNum) && (installNum <= 3999)) {
                    String label = appInfo.loadLabel(pm).toString();
                    Drawable drawable = appInfo.loadIcon(pm);
                    dataList.add(new MyAppInfo(sourceDir, label, drawable, eval, installNum));
                }

            }
        }

        Collections.sort(dataList, new MyAppInfoComparator());

        adapter.notifyDataSetChanged();
    }


    private class PackageListAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return dataList.size();
        }

        @Override
        public Object getItem(int position) {
            return dataList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(
                int position,
                View convertView,
                ViewGroup parent) {

            View v = convertView;
            TextView textView1;
            TextView textView2;
            TextView textView3;
            ImageView imageView1;

            if(v==null){
                LayoutInflater inflater =
                        (LayoutInflater) getSystemService(
                                Context.LAYOUT_INFLATER_SERVICE);
                v = inflater.inflate(R.layout.row, null);
            }

            MyAppInfo aInfo = (MyAppInfo)getItem(position);
            if(aInfo != null){
                textView1 = (TextView) v.findViewById(R.id.textView1);
                textView2 = (TextView) v.findViewById(R.id.textView2);
                textView3 = (TextView) v.findViewById(R.id.textView3);
                imageView1 = (ImageView) v.findViewById(R.id.imageView1);

                textView1.setText(aInfo.getLabel());
                textView2.setText(aInfo.getEval());
                textView3.setText(aInfo.getInstallNum() + "");
                imageView1.setImageDrawable(aInfo.getDrawable());
            }
            return v;
        }

    }

}
```

#MyAppInfo.java
```java:MyAppInfo.java
import android.graphics.drawable.Drawable;

public class MyAppInfo {
    String sourceDir;
    String label;
    Drawable drawable;

    String eval;
    int installNum;

    public MyAppInfo(
            String sourceDir,
            String label,
            Drawable drawable,
            String eval,
            int installNum){
        this.sourceDir = sourceDir;
        this.label = label;
        this.drawable = drawable;
        this.eval = eval;
        this.installNum = installNum;
    }

    public String getSourceDir(){
        return this.sourceDir;
    }

    public String getLabel(){
        return this.label;
    }

    public Drawable getDrawable(){
        return this.drawable;
    }

    public String getEval(){
        return this.eval;
    }

    public int getInstallNum(){
        return this.installNum;
    }
}
```

#MyAppInfoComparator.java
```java:MyAppInfoComparator.java
import java.util.Comparator;

public class MyAppInfoComparator
        implements Comparator<MyAppInfo> {
    @Override
    public int compare(MyAppInfo i1, MyAppInfo i2) {
        return i1.getLabel().compareTo(i2.getLabel());
    }
}
```

#Layout/activity_main.xml
```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:text="検索条件"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:id="@+id/ll1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView6">

        <TextView
            android:id="@+id/textView4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="アプリ評価：　　"
            android:textSize="16dp" />

        <Spinner
            android:id="@+id/spinner1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:entries="@array/spEval_label" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/ll1">

        <TextView
            android:id="@+id/textView5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="インストール数："
            android:textSize="16dp" />

        <Spinner
            android:id="@+id/spinner2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:entries="@array/spInstNum_label" />
    </LinearLayout>

    <Button
        android:id="@+id/button"
        android:layout_width="167dp"
        android:layout_height="36dp"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:text="Search!"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/ll2" />


    <LinearLayout
        android:id="@+id/ll3"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="8dp"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button">

        <View
            android:layout_width="match_parent"
            android:layout_height="5dp"
            android:background="#5353" />

        <ListView
            android:id="@+id/listView1"
            android:layout_width="match_parent"
            android:layout_height="0dip"
            android:layout_weight="1" />
    </LinearLayout>


</android.support.constraint.ConstraintLayout>
```

#Layout/row.xml
```xml:row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dip">
    <ImageView
        android:contentDescription=""
        android:id="@+id/imageView1"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_gravity="center_vertical"
        android:layout_margin="5dip"/>
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:textSize="18sp"
            android:id="@+id/textView1"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="5dip"/>
        <TextView
            android:textSize="12sp"
            android:id="@+id/textView2"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:layout_marginLeft="5dp"/>
        <TextView
            android:textSize="12sp"
            android:id="@+id/textView3"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:layout_marginLeft="5dp"/>
    </LinearLayout>
</LinearLayout>
```

#Layout/string.xml
```xml:string.xml
<resources>
    <string name="app_name">TestAppFilter</string>

    <array name="spEval_label">
        <item>指定なし</item>
        <item>星1</item>
        <item>星2</item>
        <item>星3</item>
    </array>

    <array name="spInstNum_label">
        <item>指定なし</item>
        <item>1000~1999</item>
        <item>2000~2999</item>
        <item>3000~3999</item>
    </array>

</resources>
```

おわり。