Java tutorial
/* * Copyright (C) 2013 Dario Scoppelletti, <http://www.scoppelletti.it/>. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package it.scoppelletti.mobilepower.app; import java.lang.reflect.*; import java.util.*; import android.app.*; import android.content.*; import android.content.pm.*; import android.content.res.*; import android.os.*; import android.preference.*; import android.support.v4.app.*; import android.view.*; import org.apache.commons.lang3.*; import org.slf4j.*; import it.scoppelletti.mobilepower.os.*; import it.scoppelletti.mobilepower.reflect.*; import it.scoppelletti.mobilepower.ui.resources.R; /** * Classe di base delle attività. * * @since 1.0 */ public abstract class AbstractActivity extends FragmentActivity implements ActivitySupport, MemberCache.Resolver { private static final int METHOD_GETACTIONBAR = 1; private static final Logger myLogger = LoggerFactory.getLogger("AbstractActivity"); private final Set<String> myDialogSet; private boolean myStartup; private int myInitIdx; /** * Costruttore. */ protected AbstractActivity() { myDialogSet = new HashSet<String>(); myStartup = false; myInitIdx = 0; } public final Activity asActivity() { return this; } public final ActionBarSupport getSupportActionBar() { Object actionBar; Method method; if (Build.VERSION.SDK_INT < BuildCompat.VERSION_CODES.HONEYCOMB) { return null; } try { method = (Method) MemberCache.getInstance().getMember(getClass(), AbstractActivity.METHOD_GETACTIONBAR, this); actionBar = method.invoke(this, new Object[] {}); } catch (Exception ex) { myLogger.error("Failed to get actionBar property.", ex); return null; } return new ActionBarCompat(actionBar); } /** * Creazione dell’attività. * * @param savedInstanceState Stato dell’istanza. */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTheme(AppUtils.getActivityTheme()); myStartup = (savedInstanceState == null); } /** * Ripristina lo stato dell’istanza. * * @param savedInstanceState Stato dell’istanza. */ @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { Fragment fragment; DialogFragment dlg; FragmentManager fragmentMgr; super.onRestoreInstanceState(savedInstanceState); fragmentMgr = getSupportFragmentManager(); for (String tag : myDialogSet) { fragment = fragmentMgr.findFragmentByTag(tag); if (fragment == null) { myLogger.trace("Fragment {} not found.", tag); continue; } if (!(fragment instanceof DialogFragment)) { myLogger.warn("Fragment {} is not dialog.", tag); continue; } dlg = (DialogFragment) fragment; dlg.dismiss(); } } /** * Avvia il successivo processo asincrono di inizializzazione. * * <P>Se l’attività richiede dei processi asincroni di * inizializzazione, deve:</P> * * <OL> * <LI>Implementare una versione prevalente del metodo * {@code onAsyncInitializer} per avviare ciascun processo di * inizializzazione. * <LI>Eseguire il metodo {@code onNextAsyncInitializer} al termine del * metodo {@code onCreate}. * </OL> * * <P>L’implementazione di ciascun processo asincrono di * inizializzazione deve eseguire il metodo {@code onNextAsyncInitializer} * al termine del proprio task.</P> * * @see #onAsyncInitializer */ public final void onNextAsyncInitializer() { int idx = myInitIdx; myInitIdx++; myLogger.debug("Calling onAsyncInitializer({}, {}).", idx, myStartup); onAsyncInitializer(idx, myStartup); } /** * Avvia un processo asincrono di inizializzazione. * * @param taskIdx Indice del processo. * @param startup Indicatore di attività in fase di avvio. * @see #onNextAsyncInitializer */ protected void onAsyncInitializer(int taskIdx, boolean startup) { } /** * Gestione della selezione di una voce di menù. * * @param item Voce di menù * @return Indicatore di evento gestito. */ @Override public boolean onOptionsItemSelected(MenuItem item) { int action = item.getItemId(); switch (action) { case ActionBarSupport.HOME: backToHome(); return true; } return super.onOptionsItemSelected(item); } /** * Gestisce il risultato delle attività avviate. * * @param requestCode Codice della richiesta. * @param resultCode Risultato dell’attività. * @param data Dati trasmessi dall’attività. */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case ActivitySupport.REQ_RELEASENOTES: onNextAsyncInitializer(); break; } } /** * Ripristina la configurazione dei frammenti iniziale. */ protected final void backToHome() { int n; FragmentManager fragmentMgr = getSupportFragmentManager(); for (n = fragmentMgr.getBackStackEntryCount(); n > 0; n--) { fragmentMgr.popBackStack(); } } public final void onDialogFragmentShow(String tag) { if (StringUtils.isBlank(tag)) { throw new NullPointerException("Argument tag is null."); } if (!myDialogSet.add(tag)) { myLogger.warn("Duplicate dialog {}.", tag); } } public final void onDialogFragmentDismiss(String tag) { if (StringUtils.isBlank(tag)) { throw new NullPointerException("Argument tag is null."); } if (!myDialogSet.remove(tag)) { myLogger.warn("Dialog {} not found.", tag); } } public Member resolveMember(Class<?> clazz, int memberCode) { Member member; try { switch (memberCode) { case AbstractActivity.METHOD_GETACTIONBAR: member = clazz.getMethod("getActionBar"); break; default: throw new NoSuchMethodException(String.format("Unexpected memberCode %1$d.", memberCode)); } } catch (Exception ex) { throw new UnsupportedOperationException(ex.getMessage(), ex); } return member; } /** * Visualizza le note di rilascio. * * <P>Le classi derivate posso eseguire questo metodo all’interno * della propria versione prevalente del metodo * {@code onAsyncInitializer}.</P> * * @param resId Identificatore del vettore di stringhe che rappresenta le * note di release. * @see #onAsyncInitializer * @see #onNextAsyncInitializer * @see it.scoppelletti.mobilepower.ui.app.ReleaseNoteActivity */ protected final void showReleaseNotes(int resId) { String notes; Intent intent; notes = buildReleaseNotes(resId); if (StringUtils.isBlank(notes)) { onNextAsyncInitializer(); return; } intent = new Intent(ReleaseNoteActivity.ACTION_RELEASENOTES); intent.setPackage(getPackageName()); intent.putExtra(ReleaseNoteActivity.EXTRA_RELEASENOTES, notes); startActivityForResult(intent, ActivitySupport.REQ_RELEASENOTES); } /** * Costruisce il testo delle note di rilascio. * * @param resId Identificatore del vettore di stringhe che rappresenta le * note di release. * @return Testo. Può essere {@code null}. */ private String buildReleaseNotes(int resId) { int n; int ver, lastVer; String note, pkgName; StringBuilder buf; PackageInfo pkgInfo; PackageManager pkgMgr; SharedPreferences prefs; SharedPreferences.Editor editor; String[] notes; try { notes = getResources().getStringArray(resId); } catch (Resources.NotFoundException ex) { myLogger.debug("Release notes {} not found.", resId); return null; } if (ArrayUtils.isEmpty(notes)) { myLogger.warn("Release notes {} is empty.", resId); onNextAsyncInitializer(); return null; } pkgName = getPackageName(); pkgMgr = getPackageManager(); try { pkgInfo = pkgMgr.getPackageInfo(pkgName, 0); } catch (PackageManager.NameNotFoundException ex) { myLogger.error("Failed to get PackageInfo.", ex); pkgInfo = null; } if (pkgInfo == null) { myLogger.debug("No PackagerInfo set."); return null; } ver = pkgInfo.versionCode; prefs = PreferenceManager.getDefaultSharedPreferences(this); lastVer = prefs.getInt(AppUtils.PREF_LASTVER, 1); myLogger.debug("Version code={}, Last version code={}", ver, lastVer); editor = prefs.edit(); editor.putInt(AppUtils.PREF_LASTVER, ver); editor.apply(); if (ver == 1 || ver <= lastVer) { return null; } ver -= 2; lastVer = (lastVer > 0) ? lastVer - 2 : -1; buf = new StringBuilder(); for (n = notes.length - 1; ver > lastVer; ver--) { if (ver > n) { continue; } note = notes[ver]; if (StringUtils.isBlank(note)) { continue; } buf.append(note); } if (buf.length() == 0) { return null; } buf.insert(0, "</h1>"); buf.insert(0, getString(R.string.lbl_releaseNotes)); buf.insert(0, "<h1>"); return buf.toString(); } }