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

Last change on this file since 42e7061 was 6141013, checked in by Jose Ruiz <joseruiz@…>, 11 years ago

Corrección de error en el repositorio de certificados 'Sin acceso al repositorio'

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