source: dispositivos_moviles/TibisayMovil/src/ve/gob/cenditel/tibisaymovil/KeyChainActivity.java @ c14b8d2

Last change on this file since c14b8d2 was 288126d, checked in by Jose Ruiz <joseruiz@…>, 11 years ago

Manejo de repositorio de certificados y firma con pkcs7

  • Property mode set to 100644
File size: 14.2 KB
Line 
1/*
2 * Copyright (C) 2011 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 ve.gob.cenditel.tibisaymovil;
18
19import java.security.cert.X509Certificate;
20import java.util.ArrayList;
21import java.util.Collections;
22import java.util.List;
23
24
25import android.app.Activity;
26import android.content.Intent;
27import android.os.AsyncTask;
28import android.os.Bundle;
29import android.util.SparseBooleanArray;
30import android.view.LayoutInflater;
31import android.view.Menu;
32import android.view.MenuItem;
33import android.view.View;
34import android.view.Window;
35import android.view.View.OnClickListener;
36import android.view.ViewGroup;
37import android.widget.AdapterView;
38import android.widget.AdapterView.OnItemClickListener;
39import android.widget.BaseAdapter;
40import android.widget.Button;
41import android.widget.CheckBox;
42import android.widget.ImageView;
43import android.widget.ListView;
44import android.widget.TextView;
45import android.widget.Toast;
46
47/**
48 * Activity that mimics the Android >= 4.0 Keychain. {@link KeyChainStrategy} automatically starts this activity
49 * when needed.
50 *
51 * @author José M. Prieto (jmprieto@emergya.com)
52 */
53public class KeyChainActivity extends Activity implements OnClickListener, OnItemClickListener {
54
55    private KeyChainView viewHolder;
56    private CustomKeyChain keyChain;
57    private int numChecks;
58        private CertificateAdapter adapt;
59   
60    @Override
61    public void onCreate(Bundle savedInstanceState) {
62                //Estilando la barra de titulo
63                final boolean customTitleSupported = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
64
65        super.onCreate(savedInstanceState);
66 
67
68        this.keyChain = CustomKeyChain.getInstance();
69        this.viewHolder = new KeyChainView();
70       
71        //Eliminate menu. Not used for now.
72        if (this.getIntent()!=null){
73               
74                boolean quitmenu = this.getIntent().getBooleanExtra("quitmenu", false);
75                if (quitmenu) {
76                        this.viewHolder.accept.setVisibility(View.GONE);
77                        this.viewHolder.cancel.setVisibility(View.GONE);
78                }
79        }else{
80                this.viewHolder.accept.setVisibility(View.VISIBLE);
81                this.viewHolder.cancel.setVisibility(View.VISIBLE);
82        }
83       
84
85
86        try {
87                this.adapt = new KeyChainActivity.CertificateAdapter(this.keyChain);
88            this.viewHolder.aliases.setAdapter(adapt);
89        } catch (KeystoreException e) {
90            Toast.makeText(this, R.string.error_unknown, Toast.LENGTH_LONG).show();
91            //throw new RuntimeException(e);
92        }
93
94       
95        if (this.adapt!=null && this.adapt.aliases.size()==1){
96                this.numChecks=1;
97                        this.viewHolder.aliases.setItemChecked(0, true);
98        }else
99                this.numChecks = 0;
100
101        this.updateCheckedNumber();
102        this.updateButtons();
103
104        //Estilando Barra de titulo
105                if(customTitleSupported)
106                        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.title_bar);
107   
108
109    }
110   
111    @Override
112    protected void onResume(){
113        super.onResume();
114       
115        //TODO:
116        this.keyChain.reloadKeyStore();
117        if (this.adapt!=null)
118                this.adapt.notifyDataSetChanged();
119
120    }
121
122        @Override
123    protected void onSaveInstanceState(Bundle outState) {
124
125        super.onSaveInstanceState(outState);
126        outState.putInt("numChecks", this.numChecks);
127    }
128
129    @Override
130    public boolean onCreateOptionsMenu(Menu menu) {
131
132        /*getMenuInflater().inflate(R.menu.keychain_menu, menu);*/
133        return true;
134    }
135
136    @Override
137    public boolean onOptionsItemSelected(MenuItem item) {
138
139        switch (item.getItemId()) {
140        case R.id.change_password:
141            changePassword();
142            return true;
143
144        default:
145            return super.onOptionsItemSelected(item);
146        }
147    }
148
149    @Override
150    public void onClick(View view) {
151
152        switch (view.getId()) {
153
154        case R.id.cert_chooser_install_button:
155            Intent intent = new Intent(this, PKCS12FilePickerActivity.class);
156            startActivityForResult(intent, ActivityResult.IMPORT_CERTIFICATE);
157            break;
158
159        case R.id.button_cancel:
160            setResult(RESULT_CANCELED);
161            finish();
162            break;
163
164        case R.id.button_accept:
165                if (this.numChecks==1){
166                        acceptSelectedCertificate();
167                }
168       
169                break;
170           
171        case R.id.button_delete:
172                if (this.numChecks>0)
173                        deleteSelectedCertificates();
174            break;
175           
176        }
177    }
178   
179 
180   
181
182    private void acceptSelectedCertificate() {
183
184        Toast.makeText(this, "accept", Toast.LENGTH_LONG).show();
185        SparseBooleanArray checkedItems = this.viewHolder.aliases.getCheckedItemPositions();
186                boolean found=false;
187                int firstPosition=-1;
188               
189                for (int i = 0; i < checkedItems.size() && found==false; i++) {
190
191                Toast.makeText(this, "i="+i, Toast.LENGTH_LONG).show();
192                        if( checkedItems.valueAt(i)== true){
193                                found=true;
194                                firstPosition=checkedItems.keyAt(i);
195                        }
196                }
197               
198                if (firstPosition!=-1){
199                        KeyChainStrategy.activity.setAlias((String) this.viewHolder.aliases.getItemAtPosition(firstPosition));                 
200                        setResult(Activity.RESULT_OK);
201                        finish();       
202                }
203        }
204
205   
206        private void deleteSelectedCertificates() {
207
208                SparseBooleanArray checkedItems = this.viewHolder.aliases.getCheckedItemPositions();
209               
210                for (int i = 0; i < checkedItems.size(); i++) {
211                        if(checkedItems.valueAt(i) == true){
212                               
213                                try {
214                                        int position = checkedItems.keyAt(i);
215                                        KeyChainStrategy.getInstance().deleteCertificate(
216                                                        (String) this.viewHolder.aliases.getItemAtPosition(position));
217                                } catch (KeystoreException e) {
218                                        e.printStackTrace();
219                                } catch (InterruptedException e) {
220                                        e.printStackTrace();
221                                }
222                        }
223                }
224       
225                //Refresh adapter. NotifyDataSetChange didnt work.
226                try {
227                        KeyChainActivity.this.viewHolder.aliases.setAdapter(
228                                new CertificateAdapter(KeyChainActivity.this.keyChain));
229                } catch (KeystoreException e) {
230                        e.printStackTrace();
231                }
232                this.updateCheckedNumber();
233                this.updateButtons();
234               
235               
236                //Refresh KeyChain for external views.
237                try {
238                        this.keyChain.saveKeystore();
239                        this.keyChain.reloadKeyStore();
240                } catch (KeystoreException e) {
241                } catch (OutOfSpaceError e) {
242                }
243               
244        }
245       
246
247        @Override
248    public void onItemClick(AdapterView<?> parent, View view, int item, long id) {
249        this.updateCheckedNumber();
250        this.updateButtons();
251    }
252
253        private void updateButtons() {
254                this.viewHolder.delete.setEnabled(this.numChecks>0);
255                this.viewHolder.accept.setEnabled(this.numChecks==1);
256               
257        }
258
259    private void updateCheckedNumber() {
260                SparseBooleanArray checkedItems = this.viewHolder.aliases.getCheckedItemPositions();
261                int count = 0;
262                for (int i = 0; i < checkedItems.size(); i++) {
263                                if (checkedItems.valueAt(i))
264                                        count++;
265                }
266                this.numChecks = count;         
267        }
268
269        @Override
270    protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
271
272        if (requestCode == ActivityResult.IMPORT_CERTIFICATE && resultCode == Activity.RESULT_OK) {
273            final PasswordDialog dialog = new PasswordDialog(this, R.string.certificate_password, false);
274            dialog.setAcceptListener(new OnClickListener() {
275
276                @Override
277                public void onClick(View v) {
278
279                    try {
280                        int imported = KeyChainActivity.this.keyChain.importCertificate(data.getData(), dialog.getPassword());
281                        KeyChainActivity.this.keyChain.saveKeystore();
282                        String text = KeyChainActivity.this.getResources().getQuantityString(R.plurals.number_imported_certificates, imported, imported);
283                        Toast.makeText(KeyChainActivity.this, text, Toast.LENGTH_LONG).show();
284                        KeyChainActivity.this.viewHolder.aliases.setAdapter(
285                                new CertificateAdapter(KeyChainActivity.this.keyChain));
286                    } catch (IncorrectPasswordException e) {
287                        Toast toast = Toast.makeText(KeyChainActivity.this, R.string.incorrect_password, Toast.LENGTH_LONG);
288                        toast.show();
289                    } catch (Exception e) {
290                        Toast toast = Toast.makeText(KeyChainActivity.this, R.string.error_reading_p12, Toast.LENGTH_LONG);
291                        toast.show();
292                    }
293                    dialog.dismiss();
294                }
295            });
296            dialog.show();
297        }
298    }
299
300    public void changePassword() {
301        final PasswordConfirmationDialog dialog =
302                new PasswordConfirmationDialog(this, R.string.keystore_new_password);
303        dialog.setAcceptListener(new OnClickListener() {
304
305            @Override
306            public void onClick(View v) {
307                String newPassword = dialog.getPassword();
308                dialog.dismiss();
309                try {
310                    KeyChainActivity.this.keyChain.saveKeystore(newPassword);
311                    Toast.makeText(KeyChainActivity.this, R.string.password_change_success, Toast.LENGTH_LONG).show();
312                } catch (OutOfSpaceError e) {
313                    Toast.makeText(KeyChainActivity.this, R.string.error_no_space, Toast.LENGTH_LONG).show();
314                } catch (KeystoreException e) {
315                    Toast.makeText(KeyChainActivity.this, R.string.error_unknown, Toast.LENGTH_LONG).show();
316                    //throw new RuntimeException(e);
317                }
318            }
319        });
320        dialog.show();
321    }
322   
323
324    private class CertificateAdapter extends BaseAdapter {
325
326        private final List<String> aliases;
327        private final List<String> subjects = new ArrayList<String>();
328        private CustomKeyChain keyChain;
329
330        private CertificateAdapter(CustomKeyChain keyChain)
331        throws KeystoreException {
332
333            this.aliases = Collections.list(keyChain.getAliases());
334            this.subjects.addAll(Collections.nCopies(this.aliases.size(), (String) null));
335            this.keyChain = keyChain;
336        }
337
338        @Override public int getCount() {
339
340            return this.aliases.size();
341        }
342
343        @Override public String getItem(int adapterPosition) {
344
345            return this.aliases.get(adapterPosition);
346        }
347
348        @Override public long getItemId(int adapterPosition) {
349
350            return adapterPosition;
351        }
352
353        @Override public View getView(final int position, View convertView, ViewGroup parent) {
354
355            if (convertView == null) {
356                LayoutInflater inflater = LayoutInflater.from(KeyChainActivity.this);
357                convertView = inflater.inflate(R.layout.cert_item, parent, false);
358            }
359
360            TextView aliasTextView = (TextView) convertView.findViewById(R.id.cert_item_alias);
361            TextView subjectTextView = (TextView) convertView.findViewById(R.id.cert_item_subject);
362            CheckBox checkBox = (CheckBox) convertView.findViewById(R.id.cert_item_selected);
363
364            String alias = this.aliases.get(position);
365            convertView.setTag(alias);
366            aliasTextView.setText(alias);
367
368            String subject = this.subjects.get(position);
369            if (subject == null) {
370                new CertLoader(position, subjectTextView, this.keyChain).execute();
371            } else {
372                subjectTextView.setText(subject);
373            }
374
375           
376           
377            ListView lv = (ListView)parent;
378           
379         
380            checkBox.setChecked(lv.getCheckedItemPositions().get(position));
381           
382            return convertView;
383        }
384
385        private class CertLoader extends AsyncTask<Void, Void, String> {
386
387            private final int adapterPosition;
388            private final TextView subjectView;
389            private CustomKeyChain keyChain;
390
391            private CertLoader(int adapterPosition, TextView subjectView, CustomKeyChain keyChain) {
392
393                this.adapterPosition = adapterPosition;
394                this.subjectView = subjectView;
395                this.keyChain = keyChain;
396            }
397
398            @Override protected String doInBackground(Void... params) {
399
400                String alias = CertificateAdapter.this.aliases.get(this.adapterPosition);
401                X509Certificate cert;
402                try {
403                    cert = this.keyChain.getCertificateChain(alias)[0];
404                    // bouncycastle can handle the emailAddress OID of 1.2.840.113549.1.9.1
405                    return cert.getSubjectDN().getName();
406                } catch (KeystoreException e) {
407                    return "";
408                }
409            }
410
411            @Override protected void onPostExecute(String subjectString) {
412
413                CertificateAdapter.this.subjects.set(this.adapterPosition, subjectString);
414                this.subjectView.setText(subjectString);
415            }
416        }
417    }
418
419    private class KeyChainView {
420
421        public ListView aliases;
422        public TextView install;
423        public ImageView accept;
424        public ImageView cancel;
425        public TextView delete;
426
427        public KeyChainView() {
428
429            setContentView(R.layout.cert_chooser);
430
431            this.aliases = (ListView) findViewById(R.id.cert_chooser);
432            this.aliases.setOnItemClickListener(KeyChainActivity.this);
433
434            this.install = (TextView) findViewById(R.id.cert_chooser_install_button);
435            this.install.setOnClickListener(KeyChainActivity.this);
436
437            this.accept = (ImageView) findViewById(R.id.button_accept);
438            this.accept.setOnClickListener(KeyChainActivity.this);
439
440            this.cancel = (ImageView) findViewById(R.id.button_cancel);
441            this.cancel.setOnClickListener(KeyChainActivity.this);
442           
443            this.delete = (TextView) findViewById(R.id.button_delete);
444            this.delete.setOnClickListener(KeyChainActivity.this);         
445           
446        }
447    }
448}
Note: See TracBrowser for help on using the repository browser.