it.scoppelletti.mobilepower.app.AbstractActivity.java Source code

Java tutorial

Introduction

Here is the source code for it.scoppelletti.mobilepower.app.AbstractActivity.java

Source

/*
 * 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&agrave;.
 * 
 * @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&rsquo;attivit&agrave;.
     * 
     * @param savedInstanceState Stato dell&rsquo;istanza.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setTheme(AppUtils.getActivityTheme());
        myStartup = (savedInstanceState == null);
    }

    /**
     * Ripristina lo stato dell&rsquo;istanza.
     * 
     * @param savedInstanceState Stato dell&rsquo;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&rsquo;attivit&agrave; 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&rsquo;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&agrave; in fase di avvio.
     * @see           #onNextAsyncInitializer 
     */
    protected void onAsyncInitializer(int taskIdx, boolean startup) {
    }

    /**
     * Gestione della selezione di una voce di men&ugrave;.
     * 
     * @param  item Voce di men&ugrave;
     * @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&agrave; avviate.
     * 
     * @param requestCode Codice della richiesta.
     * @param resultCode  Risultato dell&rsquo;attivit&agrave;.
     * @param data        Dati trasmessi dall&rsquo;attivit&agrave;.
     */
    @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&rsquo;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&ograve; 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();
    }
}