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

Last change on this file since 8379cd8 was 8379cd8, checked in by Antonio Araujo Brett <aaraujo@…>, 11 years ago

Agregado encabezado de licencia a archivos fuentes.

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