Revision 9e69afe0

View differences:

res/layout/activity_main.xml
1
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
1
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 2
    xmlns:tools="http://schemas.android.com/tools"
3
    android:layout_width="match_parent"
4
    android:layout_height="match_parent" >
3
    android:layout_width="fill_parent"
4
    android:layout_height="fill_parent"
5
    android:orientation="vertical" >
6

  
7
    <TableLayout
8
        android:layout_width="match_parent"
9
        android:layout_height="wrap_content"
10
        android:paddingBottom="5dip"
11
        android:paddingTop="5dip" >
12

  
13
        <TableRow
14
            android:layout_width="wrap_content"
15
            android:layout_height="wrap_content" >
16

  
17
            <TextView
18
                android:layout_width="wrap_content"
19
                android:layout_height="wrap_content"
20
                android:layout_gravity="right|center_vertical"
21
                android:text="SubjectDN:"
22
                android:typeface="monospace" />
23

  
24
            <TextView
25
                android:id="@+id/subjectdn"
26
                android:layout_width="wrap_content"
27
                android:layout_height="wrap_content" />
28
        </TableRow>
29

  
30
        <TableRow
31
            android:layout_width="wrap_content"
32
            android:layout_height="wrap_content" >
33

  
34
            <TextView
35
                android:layout_width="wrap_content"
36
                android:layout_height="wrap_content"
37
                android:layout_gravity="right|center_vertical"
38
                android:text="IssuerDN:"
39
                android:typeface="monospace" />
40

  
41
            <TextView
42
                android:id="@+id/issuerdn"
43
                android:layout_width="wrap_content"
44
                android:layout_height="wrap_content" />
45
        </TableRow>
46
    </TableLayout>
5 47

  
6 48
    <fragment
7 49
        android:id="@+id/fragment_app_list"
50
        android:name="info.guardianproject.checkey.MainActivity$AppListFragment"
8 51
        android:layout_width="fill_parent"
9
        android:layout_height="fill_parent"
10
        class="info.guardianproject.checkey.AppListFragment" />
52
        android:layout_height="wrap_content" />
11 53

  
12
</RelativeLayout>
54
</LinearLayout>
res/menu/context.xml
1
<?xml version="1.0" encoding="utf-8"?>
2
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
3

  
4
    <item
5
        android:id="@+id/save"
6
        android:icon="@android:drawable/ic_menu_save"
7
        android:showAsAction="ifRoom|withText"
8
        android:title="@string/save"/>
9
    <item
10
        android:id="@+id/virustotal"
11
        android:icon="@drawable/virustotal"
12
        android:showAsAction="ifRoom|withText"
13
        android:title="@string/virustotal"/>
14
    <item
15
        android:id="@+id/by_apk_hash"
16
        android:showAsAction="ifRoom|withText"
17
        android:title="@string/by_apk_hash"/>
18
    <item
19
        android:id="@+id/by_package_name"
20
        android:showAsAction="ifRoom|withText"
21
        android:title="@string/by_package_name"/>
22
    <item
23
        android:id="@+id/by_signing_certificate"
24
        android:showAsAction="ifRoom|withText"
25
        android:title="@string/by_signing_certificate"/>
26

  
27
</menu>
res/menu/main.xml
4 4
    tools:context="info.guardianproject.checkey.MainActivity" >
5 5

  
6 6
    <item
7
        android:id="@+id/save"
8
        android:icon="@android:drawable/ic_menu_save"
9
        android:showAsAction="ifRoom|withText"
10
        android:title="@string/save"/>
11
    <item
12
        android:id="@+id/virustotal"
13
        android:icon="@drawable/virustotal"
14
        android:showAsAction="ifRoom|withText"
15
        android:title="@string/virustotal"/>
16
    <item
17
        android:id="@+id/by_apk_hash"
18
        android:showAsAction="ifRoom|withText"
19
        android:title="@string/by_apk_hash"/>
20
    <item
21
        android:id="@+id/by_package_name"
22
        android:showAsAction="ifRoom|withText"
23
        android:title="@string/by_package_name"/>
24
    <item
25
        android:id="@+id/by_signing_certificate"
26
        android:showAsAction="ifRoom|withText"
27
        android:title="@string/by_signing_certificate"/>
28
    <item
7 29
        android:id="@+id/action_settings"
8 30
        android:icon="@android:drawable/ic_menu_preferences"
9 31
        android:orderInCategory="100"
src/info/guardianproject/checkey/AppListFragment.java
1
/*
2
 Licensed under the Apache License, Version 2.0 (the "License");
3
 you may not use this file except in compliance with the License.
4
You may obtain a copy of the License at
5

  
6
    http://www.apache.org/licenses/LICENSE-2.0
7

  
8
Unless required by applicable law or agreed to in writing, software
9
distributed under the License is distributed on an "AS IS" BASIS,
10
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
See the License for the specific language governing permissions and
12
limitations under the License.
13

  
14
Based on Paul Blundell's Tutorial:
15
http://blog.blundell-apps.com/tut-asynctask-loader-using-support-library/
16

  
17
which is originally based on:
18
https://developer.android.com/reference/android/content/AsyncTaskLoader.html
19
 */
20

  
21
package info.guardianproject.checkey;
22

  
23
import android.app.Activity;
24
import android.content.Context;
25
import android.content.Intent;
26
import android.content.pm.PackageInfo;
27
import android.content.pm.PackageManager;
28
import android.content.pm.PackageManager.NameNotFoundException;
29
import android.content.pm.Signature;
30
import android.net.Uri;
31
import android.os.Bundle;
32
import android.support.v4.app.ListFragment;
33
import android.support.v4.app.LoaderManager.LoaderCallbacks;
34
import android.support.v4.content.Loader;
35
import android.support.v7.app.ActionBarActivity;
36
import android.support.v7.view.ActionMode;
37
import android.view.Menu;
38
import android.view.MenuInflater;
39
import android.view.MenuItem;
40
import android.view.View;
41
import android.webkit.WebView;
42
import android.widget.ListView;
43
import android.widget.Toast;
44

  
45
import java.io.ByteArrayInputStream;
46
import java.io.FileNotFoundException;
47
import java.io.FileOutputStream;
48
import java.io.IOException;
49
import java.io.InputStream;
50
import java.io.UnsupportedEncodingException;
51
import java.security.NoSuchAlgorithmException;
52
import java.security.cert.CertificateException;
53
import java.security.cert.CertificateFactory;
54
import java.security.cert.X509Certificate;
55
import java.util.List;
56

  
57
public class AppListFragment extends ListFragment implements LoaderCallbacks<List<AppEntry>> {
58

  
59
    private PackageManager pm;
60
    private AppListAdapter adapter;
61
    private ActionMode actionMode;
62
    private ListView listView;
63
    private int selectedItem = -1;
64
    private static final String STATE_CHECKED = "info.guardianproject.checkey.STATE_CHECKED";
65
    WebView androidObservatoryView;
66

  
67
    @Override
68
    public void onActivityCreated(Bundle savedInstanceState) {
69
        super.onActivityCreated(savedInstanceState);
70

  
71
        setEmptyText(getString(R.string.no_applications_found));
72

  
73
        adapter = new AppListAdapter(getActivity());
74
        setListAdapter(adapter);
75
        setListShown(false);
76

  
77
        listView = getListView();
78
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
79

  
80
        if (savedInstanceState != null) {
81
            int position = savedInstanceState.getInt(STATE_CHECKED, -1);
82
            if (position > -1) {
83
                listView.setItemChecked(position, true);
84
            }
85
        }
86

  
87
        // Prepare the loader
88
        // either reconnect with an existing one or start a new one
89
        getLoaderManager().initLoader(0, null, this);
90
    }
91

  
92
    @Override
93
    public void onSaveInstanceState(Bundle savedInstanceState) {
94
        super.onSaveInstanceState(savedInstanceState);
95
        savedInstanceState.putInt(STATE_CHECKED, selectedItem);
96
    }
97

  
98
    @Override
99
    public void onListItemClick(ListView l, View v, int position, long id) {
100
        if (actionMode != null) {
101
            return;
102
        }
103

  
104
        // Start the CAB using the ActionMode.Callback defined above
105
        ActionBarActivity activity = (ActionBarActivity) getActivity();
106
        actionMode = activity.startSupportActionMode(mActionModeCallback);
107
        selectedItem = position;
108
    }
109

  
110
    private void saveCertificate(AppEntry appEntry, Intent intent) {
111
        if (pm == null)
112
            pm = getActivity().getApplicationContext().getPackageManager();
113
        Activity activity = getActivity();
114
        String packageName = appEntry.getPackageName();
115
        PackageInfo pkgInfo;
116
        try {
117
            pkgInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
118
            CertificateFactory certFactory = CertificateFactory.getInstance("X509");
119
            for (Signature sig : pkgInfo.signatures) {
120
                byte[] cert = sig.toByteArray();
121
                InputStream inStream = new ByteArrayInputStream(cert);
122
                X509Certificate x509 = (X509Certificate) certFactory.generateCertificate(inStream);
123

  
124
                String fileName = packageName + ".cer";
125
                final FileOutputStream os = activity.openFileOutput(fileName,
126
                        Context.MODE_WORLD_READABLE);
127
                os.write(cert);
128
                os.close();
129

  
130
                String subject = packageName + " - " + x509.getIssuerDN().getName()
131
                        + " - " + x509.getNotAfter();
132
                Uri uri = Uri.fromFile(activity.getFileStreamPath(fileName));
133
                Intent i = new Intent(Intent.ACTION_SEND);
134
                i.setType("application/pkix-cert");
135
                i.putExtra(Intent.EXTRA_STREAM, uri);
136
                i.putExtra(Intent.EXTRA_TITLE, subject);
137
                i.putExtra(Intent.EXTRA_SUBJECT, subject);
138
                startActivity(Intent.createChooser(i, getString(R.string.save_cert_using)));
139
            }
140
        } catch (NameNotFoundException e) {
141
            e.printStackTrace();
142
        } catch (CertificateException e) {
143
            e.printStackTrace();
144
        } catch (FileNotFoundException e) {
145
            e.printStackTrace();
146
        } catch (UnsupportedEncodingException e) {
147
            e.printStackTrace();
148
        } catch (IOException e) {
149
            e.printStackTrace();
150
        }
151
    }
152

  
153
    private void virustotal(AppEntry appEntry, Intent intent) {
154
        String urlString = "https://www.virustotal.com/en/file/"
155
                + Utils.getBinaryHash(appEntry.getApkFile(), "sha256") + "/analysis/";
156
        intent.setData(Uri.parse(urlString));
157
        intent.putExtra(Intent.EXTRA_TITLE, R.string.virustotal);
158
        startActivity(intent);
159
    }
160

  
161
    private void byApkHash(AppEntry appEntry, Intent intent) {
162
        String urlString = "https://androidobservatory.org/?searchby=binhash&q="
163
                + Utils.getBinaryHash(appEntry.getApkFile(), "sha1");
164
        intent.setData(Uri.parse(urlString));
165
        intent.putExtra(Intent.EXTRA_TITLE, R.string.by_apk_hash);
166
        startActivity(intent);
167
    }
168

  
169
    private void byPackageName(AppEntry appEntry, Intent intent) {
170
        String urlString = "https://androidobservatory.org/?searchby=pkg&q="
171
                + appEntry.getPackageName();
172
        intent.setData(Uri.parse(urlString));
173
        intent.putExtra(Intent.EXTRA_TITLE, R.string.by_package_name);
174
        startActivity(intent);
175
    }
176

  
177
    private void bySigningCertificate(AppEntry appEntry, Intent intent) {
178
        String sha1;
179
        try {
180
            sha1 = Utils.getCertificateFingerprint(appEntry.getApkFile(), "sha1");
181
        } catch (NoSuchAlgorithmException e) {
182
            e.printStackTrace();
183
            Toast.makeText(getActivity(), "Cannot make fingerprint of signing certificate",
184
                    Toast.LENGTH_LONG).show();
185
            return;
186
        }
187
        intent.setData(Uri.parse("https://androidobservatory.org/?searchby=certhash&q=" + sha1));
188
        intent.putExtra(Intent.EXTRA_TITLE, R.string.by_signing_certificate);
189
        startActivity(intent);
190
    }
191

  
192
    @Override
193
    public Loader<List<AppEntry>> onCreateLoader(int id, Bundle args) {
194
        // This is called when a new loader needs to be created.
195
        // This sample only has one Loader with no arguments, so it is simple.
196
        return new AppListLoader(getActivity());
197
    }
198

  
199
    @Override
200
    public void onLoadFinished(Loader<List<AppEntry>> loader, List<AppEntry> data) {
201
        adapter.setData(data);
202

  
203
        // The list should now be shown
204
        if (isResumed()) {
205
            setListShown(true);
206
        } else {
207
            setListShownNoAnimation(true);
208
        }
209
    }
210

  
211
    @Override
212
    public void onLoaderReset(Loader<List<AppEntry>> loader) {
213
        // Clear the data in the adapter
214
        adapter.setData(null);
215
    }
216

  
217
    private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
218

  
219
        // Called when the action mode is created; startActionMode() was called
220
        @Override
221
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
222
            // Inflate a menu resource providing context menu items
223
            MenuInflater inflater = mode.getMenuInflater();
224
            inflater.inflate(R.menu.context, menu);
225
            return true;
226
        }
227

  
228
        @Override
229
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
230
            return false;
231
        }
232

  
233
        // Called when the user selects a contextual menu item
234
        @Override
235
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
236
            AppEntry appEntry = (AppEntry) adapter.getItem(selectedItem);
237
            Intent intent = new Intent(getActivity(), WebViewActivity.class);
238
            intent.putExtra(Intent.EXTRA_TEXT, appEntry.getLabel());
239
            switch (item.getItemId()) {
240
                case R.id.save:
241
                    saveCertificate(appEntry, intent);
242
                    break;
243
                case R.id.virustotal:
244
                    virustotal(appEntry, intent);
245
                    break;
246
                case R.id.by_apk_hash:
247
                    byApkHash(appEntry, intent);
248
                    break;
249
                case R.id.by_package_name:
250
                    byPackageName(appEntry, intent);
251
                    break;
252
                case R.id.by_signing_certificate:
253
                    bySigningCertificate(appEntry, intent);
254
                    break;
255

  
256
                default:
257
                    return false;
258
            }
259
            mode.finish();
260
            return true;
261
        }
262

  
263
        // Called when the user exits the action mode
264
        @Override
265
        public void onDestroyActionMode(ActionMode mode) {
266
            listView.setItemChecked(selectedItem, false);
267
            listView.clearChoices();
268
            selectedItem = -1;
269
            actionMode = null;
270
        }
271
    };
272
}
src/info/guardianproject/checkey/MainActivity.java
1 1

  
2 2
package info.guardianproject.checkey;
3 3

  
4
import android.annotation.SuppressLint;
5
import android.app.Activity;
6
import android.content.Context;
7
import android.content.Intent;
8
import android.content.pm.PackageInfo;
9
import android.content.pm.PackageManager;
10
import android.content.pm.PackageManager.NameNotFoundException;
11
import android.net.Uri;
4 12
import android.os.Bundle;
13
import android.support.v4.app.ListFragment;
14
import android.support.v4.app.LoaderManager.LoaderCallbacks;
15
import android.support.v4.content.Loader;
5 16
import android.support.v7.app.ActionBarActivity;
17
import android.util.Log;
6 18
import android.view.Menu;
7 19
import android.view.MenuItem;
20
import android.view.View;
21
import android.webkit.WebView;
22
import android.widget.ListAdapter;
23
import android.widget.ListView;
24
import android.widget.TextView;
25
import android.widget.Toast;
26

  
27
import java.io.ByteArrayInputStream;
28
import java.io.FileNotFoundException;
29
import java.io.FileOutputStream;
30
import java.io.IOException;
31
import java.io.InputStream;
32
import java.io.StringBufferInputStream;
33
import java.io.UnsupportedEncodingException;
34
import java.security.NoSuchAlgorithmException;
35
import java.security.cert.CertificateException;
36
import java.security.cert.CertificateFactory;
37
import java.security.cert.X509Certificate;
38
import java.util.Arrays;
39
import java.util.List;
40
import java.util.Properties;
8 41

  
9 42
public class MainActivity extends ActionBarActivity {
10 43
    private final String TAG = "MainActivity";
44

  
45
    private static PackageManager pm;
46
    private static CertificateFactory certificateFactory;
47
    private static int selectedItem = -1;
11 48
    private AppListFragment appListFragment = null;
12 49

  
13 50
    @Override
......
32 69

  
33 70
    @Override
34 71
    public boolean onOptionsItemSelected(MenuItem item) {
72
        ListAdapter adapter = appListFragment.getListAdapter();
73
        AppEntry appEntry = (AppEntry) adapter.getItem(selectedItem);
74
        Intent intent = new Intent(this, WebViewActivity.class);
75
        intent.putExtra(Intent.EXTRA_TEXT, appEntry.getLabel());
35 76
        switch (item.getItemId()) {
36 77
            case android.R.id.home:
37 78
                setResult(RESULT_CANCELED);
38 79
                finish();
39 80
                return true;
81
            case R.id.save:
82
                saveCertificate(appEntry, intent);
83
                return true;
84
            case R.id.virustotal:
85
                virustotal(appEntry, intent);
86
                return true;
87
            case R.id.by_apk_hash:
88
                byApkHash(appEntry, intent);
89
                return true;
90
            case R.id.by_package_name:
91
                byPackageName(appEntry, intent);
92
                return true;
93
            case R.id.by_signing_certificate:
94
                bySigningCertificate(appEntry, intent);
95
                return true;
40 96
            case R.id.action_settings:
41 97
                return true;
42 98
        }
43 99
        return super.onOptionsItemSelected(item);
44 100
    }
101

  
102
    private static X509Certificate[] getX509Certificates(Context context, String packageName) {
103
        X509Certificate[] certs = null;
104
        if (pm == null)
105
            pm = context.getApplicationContext().getPackageManager();
106
        try {
107
            PackageInfo pkgInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
108
            if (certificateFactory == null)
109
                certificateFactory = CertificateFactory.getInstance("X509");
110
            certs = new X509Certificate[pkgInfo.signatures.length];
111
            for (int i = 0; i < certs.length; i++) {
112
                byte[] cert = pkgInfo.signatures[i].toByteArray();
113
                InputStream inStream = new ByteArrayInputStream(cert);
114
                certs[i] = (X509Certificate) certificateFactory.generateCertificate(inStream);
115
            }
116
        } catch (NameNotFoundException e) {
117
            e.printStackTrace();
118
        } catch (CertificateException e) {
119
            e.printStackTrace();
120
        }
121
        return certs;
122
    }
123

  
124
    private static void showCertificateInfo(Activity activity, AppEntry appEntry) {
125
        String packageName = appEntry.getPackageName();
126
        X509Certificate[] certs = getX509Certificates(activity, packageName);
127
        if (certs == null || certs.length < 1)
128
            return;
129
        // for now, just support the first cert since that is far and away
130
        // the
131
        // most common
132
        X509Certificate cert = certs[0];
133
        TextView issuerdn = (TextView) activity.findViewById(R.id.issuerdn);
134
        issuerdn.setText(cert.getIssuerDN().getName());
135
        TextView subjectdn = (TextView) activity.findViewById(R.id.subjectdn);
136
        subjectdn.setText(cert.getSubjectDN().getName());
137
    }
138

  
139
    @SuppressLint("WorldReadableFiles")
140
    private void saveCertificate(AppEntry appEntry, Intent intent) {
141
        String packageName = appEntry.getPackageName();
142
        try {
143
            for (X509Certificate x509 : getX509Certificates(this, packageName)) {
144
                String fileName = packageName + ".cer";
145
                @SuppressWarnings("deprecation")
146
                final FileOutputStream os = openFileOutput(fileName,
147
                        Context.MODE_WORLD_READABLE);
148
                os.write(x509.getEncoded());
149
                os.close();
150

  
151
                String subject = packageName + " - " + x509.getIssuerDN().getName()
152
                        + " - " + x509.getNotAfter();
153
                Uri uri = Uri.fromFile(getFileStreamPath(fileName));
154
                Intent i = new Intent(Intent.ACTION_SEND);
155
                i.setType("application/pkix-cert");
156
                i.putExtra(Intent.EXTRA_STREAM, uri);
157
                i.putExtra(Intent.EXTRA_TITLE, subject);
158
                i.putExtra(Intent.EXTRA_SUBJECT, subject);
159
                startActivity(Intent.createChooser(i, getString(R.string.save_cert_using)));
160
            }
161
        } catch (CertificateException e) {
162
            e.printStackTrace();
163
        } catch (FileNotFoundException e) {
164
            e.printStackTrace();
165
        } catch (UnsupportedEncodingException e) {
166
            e.printStackTrace();
167
        } catch (IOException e) {
168
            e.printStackTrace();
169
        }
170
    }
171

  
172
    private void virustotal(AppEntry appEntry, Intent intent) {
173
        String urlString = "https://www.virustotal.com/en/file/"
174
                + Utils.getBinaryHash(appEntry.getApkFile(), "sha256") + "/analysis/";
175
        intent.setData(Uri.parse(urlString));
176
        intent.putExtra(Intent.EXTRA_TITLE, R.string.virustotal);
177
        startActivity(intent);
178
    }
179

  
180
    private void byApkHash(AppEntry appEntry, Intent intent) {
181
        String urlString = "https://androidobservatory.org/?searchby=binhash&q="
182
                + Utils.getBinaryHash(appEntry.getApkFile(), "sha1");
183
        intent.setData(Uri.parse(urlString));
184
        intent.putExtra(Intent.EXTRA_TITLE, R.string.by_apk_hash);
185
        startActivity(intent);
186
    }
187

  
188
    private void byPackageName(AppEntry appEntry, Intent intent) {
189
        String urlString = "https://androidobservatory.org/?searchby=pkg&q="
190
                + appEntry.getPackageName();
191
        intent.setData(Uri.parse(urlString));
192
        intent.putExtra(Intent.EXTRA_TITLE, R.string.by_package_name);
193
        startActivity(intent);
194
    }
195

  
196
    private void bySigningCertificate(AppEntry appEntry, Intent intent) {
197
        String sha1;
198
        try {
199
            sha1 = Utils.getCertificateFingerprint(appEntry.getApkFile(), "sha1");
200
        } catch (NoSuchAlgorithmException e) {
201
            e.printStackTrace();
202
            Toast.makeText(this, "Cannot make fingerprint of signing certificate",
203
                    Toast.LENGTH_LONG).show();
204
            return;
205
        }
206
        intent.setData(Uri.parse("https://androidobservatory.org/?searchby=certhash&q=" + sha1));
207
        intent.putExtra(Intent.EXTRA_TITLE, R.string.by_signing_certificate);
208
        startActivity(intent);
209
    }
210

  
211
    public static class AppListFragment extends ListFragment implements
212
            LoaderCallbacks<List<AppEntry>> {
213

  
214
        private AppListAdapter adapter;
215
        private ListView listView;
216
        private static final String STATE_CHECKED = "info.guardianproject.checkey.STATE_CHECKED";
217
        WebView androidObservatoryView;
218

  
219
        public AppListFragment() {
220
            super();
221
        }
222

  
223
        @Override
224
        public void onActivityCreated(Bundle savedInstanceState) {
225
            super.onActivityCreated(savedInstanceState);
226

  
227
            setEmptyText(getString(R.string.no_applications_found));
228

  
229
            adapter = new AppListAdapter(getActivity());
230
            setListAdapter(adapter);
231
            setListShown(false);
232

  
233
            listView = getListView();
234
            listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
235

  
236
            if (savedInstanceState != null) {
237
                int position = savedInstanceState.getInt(STATE_CHECKED, -1);
238
                if (position > -1) {
239
                    listView.setItemChecked(position, true);
240
                }
241
            }
242

  
243
            // Prepare the loader
244
            // either reconnect with an existing one or start a new one
245
            getLoaderManager().initLoader(0, null, this);
246
        }
247

  
248
        @Override
249
        public void onSaveInstanceState(Bundle savedInstanceState) {
250
            super.onSaveInstanceState(savedInstanceState);
251
            savedInstanceState.putInt(STATE_CHECKED, selectedItem);
252
        }
253

  
254
        @Override
255
        public void onListItemClick(ListView l, View v, int position, long id) {
256
            // Start the CAB using the ActionMode.Callback defined above
257
            ActionBarActivity activity = (ActionBarActivity) getActivity();
258
            selectedItem = position;
259
            AppEntry appEntry = (AppEntry) adapter.getItem(selectedItem);
260
            showCertificateInfo(activity, appEntry);
261
        }
262

  
263
        @Override
264
        public Loader<List<AppEntry>> onCreateLoader(int id, Bundle args) {
265
            // This is called when a new loader needs to be created.
266
            // This sample only has one Loader with no arguments, so it is
267
            // simple.
268
            return new AppListLoader(getActivity());
269
        }
270

  
271
        @Override
272
        public void onLoadFinished(Loader<List<AppEntry>> loader, List<AppEntry> data) {
273
            adapter.setData(data);
274

  
275
            // The list should now be shown
276
            if (isResumed()) {
277
                setListShown(true);
278
            } else {
279
                setListShownNoAnimation(true);
280
            }
281
        }
282

  
283
        @Override
284
        public void onLoaderReset(Loader<List<AppEntry>> loader) {
285
            // Clear the data in the adapter
286
            adapter.setData(null);
287
        }
288
    }
45 289
}

Also available in: Unified diff