1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings;
18
19import java.text.Collator;
20import java.util.ArrayList;
21import java.util.Collections;
22import java.util.Comparator;
23import java.util.List;
24
25import android.content.pm.PackageInfo;
26import android.content.pm.PackageManager;
27import com.android.settings.applications.AppViewHolder;
28
29import android.app.ListActivity;
30import android.content.Context;
31import android.content.Intent;
32import android.content.pm.ApplicationInfo;
33import android.os.Build;
34import android.os.Bundle;
35import android.os.Process;
36import android.view.LayoutInflater;
37import android.view.View;
38import android.view.ViewGroup;
39import android.widget.ArrayAdapter;
40import android.widget.ListView;
41
42public class AppPicker extends ListActivity {
43    private AppListAdapter mAdapter;
44
45    public static final String EXTRA_REQUESTIING_PERMISSION
46            = "com.android.settings.extra.REQUESTIING_PERMISSION";
47    public static final String EXTRA_DEBUGGABLE = "com.android.settings.extra.DEBUGGABLE";
48
49    private String mPermissionName;
50    private boolean mDebuggableOnly;
51
52    @Override
53    protected void onCreate(Bundle icicle) {
54        super.onCreate(icicle);
55
56        mPermissionName = getIntent().getStringExtra(EXTRA_REQUESTIING_PERMISSION);
57        mDebuggableOnly = getIntent().getBooleanExtra(EXTRA_DEBUGGABLE, false);
58
59        mAdapter = new AppListAdapter(this);
60        if (mAdapter.getCount() <= 0) {
61            finish();
62        } else {
63            setListAdapter(mAdapter);
64        }
65    }
66
67    @Override
68    protected void onResume() {
69        super.onResume();
70    }
71
72    @Override
73    protected void onStop() {
74        super.onStop();
75    }
76
77    @Override
78    protected void onListItemClick(ListView l, View v, int position, long id) {
79        MyApplicationInfo app = mAdapter.getItem(position);
80        Intent intent = new Intent();
81        if (app.info != null) intent.setAction(app.info.packageName);
82        setResult(RESULT_OK, intent);
83        finish();
84    }
85
86    class MyApplicationInfo {
87        ApplicationInfo info;
88        CharSequence label;
89    }
90
91    public class AppListAdapter extends ArrayAdapter<MyApplicationInfo> {
92        private final List<MyApplicationInfo> mPackageInfoList = new ArrayList<MyApplicationInfo>();
93        private final LayoutInflater mInflater;
94
95        public AppListAdapter(Context context) {
96            super(context, 0);
97            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
98            List<ApplicationInfo> pkgs = context.getPackageManager().getInstalledApplications(0);
99            for (int i=0; i<pkgs.size(); i++) {
100                ApplicationInfo ai = pkgs.get(i);
101                if (ai.uid == Process.SYSTEM_UID) {
102                    continue;
103                }
104
105                // Filter out apps that are not debuggable if required.
106                if (mDebuggableOnly) {
107                    // On a user build, we only allow debugging of apps that
108                    // are marked as debuggable.  Otherwise (for platform development)
109                    // we allow all apps.
110                    if ((ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0
111                            && "user".equals(Build.TYPE)) {
112                        continue;
113                    }
114                }
115
116                // Filter out apps that do not request the permission if required.
117                if (mPermissionName != null) {
118                    boolean requestsPermission = false;
119                    try {
120                        PackageInfo pi = getPackageManager().getPackageInfo(ai.packageName,
121                                PackageManager.GET_PERMISSIONS);
122                        if (pi.requestedPermissions == null) {
123                            continue;
124                        }
125                        for (String requestedPermission : pi.requestedPermissions) {
126                            if (requestedPermission.equals(mPermissionName)) {
127                                requestsPermission = true;
128                                break;
129                            }
130                        }
131                        if (!requestsPermission) {
132                            continue;
133                        }
134                    } catch (PackageManager.NameNotFoundException e) {
135                        continue;
136                    }
137                }
138
139                MyApplicationInfo info = new MyApplicationInfo();
140                info.info = ai;
141                info.label = info.info.loadLabel(getPackageManager()).toString();
142                mPackageInfoList.add(info);
143            }
144            Collections.sort(mPackageInfoList, sDisplayNameComparator);
145            MyApplicationInfo info = new MyApplicationInfo();
146            info.label = context.getText(R.string.no_application);
147            mPackageInfoList.add(0, info);
148            addAll(mPackageInfoList);
149        }
150
151        @Override
152        public View getView(int position, View convertView, ViewGroup parent) {
153            // A ViewHolder keeps references to children views to avoid unnecessary calls
154            // to findViewById() on each row.
155            AppViewHolder holder = AppViewHolder.createOrRecycle(mInflater, convertView);
156            convertView = holder.rootView;
157            MyApplicationInfo info = getItem(position);
158            holder.appName.setText(info.label);
159            if (info.info != null) {
160                holder.appIcon.setImageDrawable(info.info.loadIcon(getPackageManager()));
161                holder.summary.setText(info.info.packageName);
162            } else {
163                holder.appIcon.setImageDrawable(null);
164                holder.summary.setText("");
165            }
166            holder.disabled.setVisibility(View.GONE);
167            return convertView;
168        }
169    }
170
171    private final static Comparator<MyApplicationInfo> sDisplayNameComparator
172            = new Comparator<MyApplicationInfo>() {
173        public final int
174        compare(MyApplicationInfo a, MyApplicationInfo b) {
175            return collator.compare(a.label, b.label);
176        }
177
178        private final Collator collator = Collator.getInstance();
179    };
180}
181