com.albedinsky.android.support.universi.UniversiContextDelegate.java Source code

Java tutorial

Introduction

Here is the source code for com.albedinsky.android.support.universi.UniversiContextDelegate.java

Source

/*
 * =================================================================================================
 *                             Copyright (C) 2015 Martin Albedinsky
 * =================================================================================================
 *         Licensed under the Apache License, Version 2.0 or later (further "License" only).
 * -------------------------------------------------------------------------------------------------
 * You may use this file only in compliance with the License. More details and copy of this License 
 * you may obtain at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 * You can redistribute, modify or publish any part of the code written within this file but as it 
 * is described in the License, the software distributed under the License is distributed on an 
 * "AS IS" BASIS, WITHOUT WARRANTIES or CONDITIONS OF ANY KIND.
 * 
 * See the License for the specific language governing permissions and limitations under the License.
 * =================================================================================================
 */
package com.albedinsky.android.support.universi;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.CheckResult;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.XmlRes;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;

import com.albedinsky.android.support.dialog.DialogOptions;
import com.albedinsky.android.support.dialog.XmlDialog;
import com.albedinsky.android.support.dialog.manage.DialogController;
import com.albedinsky.android.support.dialog.manage.DialogXmlFactory;

/**
 * Context delegate of which implementations are used by {@link UniversiActivity}, {@link UniversiCompatActivity}
 * and {@link UniversiActivity} to provide features in unified 'fashion' regardless of context in
 * which are these features supported.
 * <p>
 * A the current version this context delegate supports features described below:
 *
 * <h4>1) {@link DialogFragment DialogFragments} management</h4>
 * This feature is supported using {@link DialogController}. This controller can be accessed via
 * {@link #getDialogController()} and custom controller can be specified via {@link #setDialogController(DialogController)}.
 * <p>
 * Without any set up this delegate can be used to show any implementation of {@link XmlDialog} via
 * {@link #showXmlDialog(int, DialogOptions)} where for such case will be created internal instance
 * of {@link DialogXmlFactory} used to inflate such dialogs from an Xml file containing a
 * <b>single dialog entry</b>.
 * <p>
 * If the associated context wants to display XmlDialogs from an Xml file containing a
 * <b>set of multiple dialog entries</b> or just simple dialogs instantiated via plain Java code it
 * need to set instance of {@link DialogController.DialogFactory} that can provide that dialogs
 * via {@link #setDialogFactory(DialogController.DialogFactory)}. Such dialogs can be than displayed
 * via {@link #showDialogWithId(int, DialogOptions)}.
 * <p>
 * Already showing dialogs can be dismissed via {@link #dismissDialogWithId(int)} or {@link #dismissXmlDialog(int)}.
 * <p>
 * If the associated context is paused (indicated via {@link #setPaused(boolean)}), invoking one of
 * {@code showDialog(...)} methods will be ignored.
 *
 * <h4>2) Connection checking</h4>
 * Check whether there is some network connection established or not can be done via {@link #isActiveNetworkConnected()}
 * or for a specific connection type via {@link #isNetworkConnected(int)} for that matter.
 *
 * @author Martin Albedinsky
 */
abstract class UniversiContextDelegate {

    /**
     * Interface ===================================================================================
     */

    /**
     * Constants ===================================================================================
     */

    /**
     * Log TAG.
     */
    // private static final String TAG = "UniversiContextDelegate";

    /**
     * Request flag indicating whether the wrapped context requested binding of its data to its view
     * hierarchy or not.
     */
    static final int REQUEST_BIND_DATA = 0x00000001;

    /**
     * Flag indicating whether the wrapped context has its view created or not.
     */
    private static final int PFLAG_VIEW_CREATED = 0x00000001;

    /**
     * Flag indicating whether the wrapped context is paused or not.
     */
    private static final int PFLAG_PAUSED = 0x00000002;

    /**
     * Static members ==============================================================================
     */

    /**
     * Members =====================================================================================
     */

    /**
     * Context that is used to access some application data and services.
     */
    final Context mContext;

    /**
     * Set of private flags specified for this delegate.
     */
    private int mPrivateFlags;

    /**
     * Set of request flags.
     */
    private int mRequestFlags;

    /**
     * Controller that is used to show and dismiss dialogs within context that uses this delegate.
     */
    private DialogController mDialogController;

    /**
     * Factory providing dialog instances for the {@link #mDialogController}.
     */
    private DialogController.DialogFactory mDialogFactory;

    /**
     * Dialog factory used to inflate dialog instances presented within a single Xml file.
     */
    private DialogXmlFactory mDialogXmlFactory;

    /**
     * Manager used to check for established/available connections.
     */
    private ConnectivityManager mConnectivityManager;

    /**
     * Constructors ================================================================================
     */

    /**
     * Creates a new instance of UniversiContextDelegate.
     *
     * @param context Context that is used to access some application data and services.
     */
    UniversiContextDelegate(@NonNull Context context) {
        this.mContext = context;
    }

    /**
     * Methods =====================================================================================
     */

    /**
     * Creates a new instance of UniversiActivityDelegate for the given <var>activity</var>.
     *
     * @param activity The activity context in which will be the new delegate used.
     * @return Ready to use context delegate.
     */
    @NonNull
    public static UniversiActivityDelegate create(@NonNull FragmentActivity activity) {
        return new UniversiActivityDelegate(activity);
    }

    /**
     * Creates a new instance of UniversiFragmentDelegate for the given <var>fragment</var>.
     *
     * @param fragment The fragment context in which will be the new delegate used.
     * @return Ready to use context delegate.
     */
    @NonNull
    public static UniversiFragmentDelegate create(@NonNull Fragment fragment) {
        return new UniversiFragmentDelegate(fragment);
    }

    /**
     * Sets a controller that should be used to show and dismiss dialogs within context that uses
     * this delegate.
     *
     * @param controller The desired controller. Can be {@code null} to use the default one.
     * @see #getDialogController()
     */
    public void setDialogController(@Nullable DialogController controller) {
        this.mDialogController = controller;
        if (mDialogFactory != null) {
            this.ensureDialogController();
            mDialogController.setDialogFactory(mDialogFactory);
        }
    }

    /**
     * Returns the controller that can be used to show and dismiss dialogs within context that uses
     * this delegate
     * <p>
     * If not specified, instance of {@link DialogController} is instantiated by default.
     *
     * @return The dialog controller of this delegate.
     * @see #setDialogController(DialogController)
     */
    @NonNull
    public DialogController getDialogController() {
        this.ensureDialogController();
        return mDialogController;
    }

    /**
     * Ensures that the dialog controller is initialized.
     */
    private void ensureDialogController() {
        if (mDialogController == null)
            this.mDialogController = instantiateDialogController();
    }

    /**
     * Creates a new instance of DialogController for the context that uses this delegate.
     *
     * @return New DialogController instance.
     */
    @NonNull
    abstract DialogController instantiateDialogController();

    /**
     * Specifies a factory that should provide dialog instances for {@link DialogController} of
     * this delegate to show.
     *
     * @param factory The desired factory. Can be {@code null} to remove the current one.
     * @see #getDialogFactory()
     * @see #showDialogWithId(int)
     * @see #showDialogWithId(int, DialogOptions)
     */
    public void setDialogFactory(@Nullable DialogController.DialogFactory factory) {
        this.mDialogFactory = factory;
        this.ensureDialogController();
        mDialogController.setDialogFactory(factory);
    }

    /**
     * Returns the current dialog factory specified for this delegate.
     *
     * @return Dialog factory or {@code null} if no factory has been specified yet.
     * @see #setDialogFactory(DialogController.DialogFactory)
     */
    @Nullable
    public DialogController.DialogFactory getDialogFactory() {
        return mDialogFactory;
    }

    /**
     * Same as {@link #showDialogWithId(int, DialogOptions)} with {@code null} options.
     */
    public boolean showDialogWithId(@IntRange(from = 0) int dialogId) {
        return showDialogWithId(dialogId, null);
    }

    /**
     * Shows a dialog that is provided by the current dialog factory under the specified <var>dialogId</var>.
     *
     * @param dialogId Id of the desired dialog to show.
     * @param options  Options for the dialog.
     * @return {@code True} if dialog has been shown, {@code false} if context that uses this delegate
     * is currently <b>paused</b> or does not have its dialog factory specified.
     * @see DialogController#showDialog(int, DialogOptions)
     * @see #setDialogFactory(DialogController.DialogFactory)
     * @see #dismissDialogWithId(int)
     */
    public boolean showDialogWithId(@IntRange(from = 0) int dialogId, @Nullable DialogOptions options) {
        if (hasPrivateFlag(PFLAG_PAUSED) || mDialogFactory == null)
            return false;
        this.ensureDialogController();
        return mDialogController.showDialog(dialogId, options);
    }

    /**
     * Dismisses a dialog that is provided by the current dialog factory under the specified <var>dialogId</var>.
     *
     * @param dialogId Id of the desired dialog to dismiss.
     * @return {@code True} if dialog has been dismissed, {@code false} if context that uses this
     * delegate is currently <b>paused</b> or does not have its dialog factory specified.
     * @see DialogController#dismissDialog(int)
     * @see #showDialogWithId(int, DialogOptions)
     */
    public boolean dismissDialogWithId(@IntRange(from = 0) int dialogId) {
        if (hasPrivateFlag(PFLAG_PAUSED) || mDialogFactory == null)
            return false;
        this.ensureDialogController();
        return mDialogController.dismissDialog(dialogId);
    }

    /**
     * Same as {@link #showXmlDialog(int, DialogOptions)} with {@code null} options.
     */
    public boolean showXmlDialog(@XmlRes int resId) {
        return showXmlDialog(resId, null);
    }

    /**
     * Like {@link #showDialogWithId(int, DialogOptions)}, but in this case will be used internal
     * instance of {@link DialogXmlFactory} to create (inflate) the desired dialog instance to be
     * shown.
     *
     * @param resId   Resource id of Xml file containing the desired dialog (its specification) to show.
     * @param options Options for the dialog.
     * @return {@code True} if dialog has been successfully inflated and shown, {@code false} if
     * context that uses this delegate is currently <b>paused</b> or dialog failed to be inflated.
     * @see DialogXmlFactory#createDialogInstance(int, DialogOptions)
     * @see #dismissXmlDialog(int)
     */
    public boolean showXmlDialog(@XmlRes int resId, @Nullable DialogOptions options) {
        if (hasPrivateFlag(PFLAG_PAUSED))
            return false;
        final DialogXmlFactory dialogFactory = accessDialogXmlFactory();
        final DialogFragment dialog = dialogFactory.createDialogInstance(resId, options);
        if (dialog != null) {
            final String dialogTag = dialogFactory.getDialogTag(resId);
            this.ensureDialogController();
            return mDialogController.showDialog(dialog, dialogTag);
        }
        return false;
    }

    /**
     * Dismisses an Xml dialog that has been shown via {@link #showXmlDialog(int, DialogOptions)}.
     *
     * @param resId Resource id of Xml file containing the desired dialog (its specification) to dismiss.
     * @return {@code True} if dialog has been dismissed, {@code false} if context that uses this
     * delegate is currently <b>paused</b>.
     * @see #showXmlDialog(int, DialogOptions)
     */
    public boolean dismissXmlDialog(@XmlRes int resId) {
        if (hasPrivateFlag(PFLAG_PAUSED))
            return false;
        this.ensureDialogController();
        return mDialogController.dismissDialog(accessDialogXmlFactory().getDialogTag(resId));
    }

    /**
     * Ensures that the dialog Xml factory is initialized and returns it. If {@link #mDialogFactory}
     * is instance of {@link DialogXmlFactory} than it will be returned.
     *
     * @return Instance of DialogXmlFactory that can be used to create instances of Xml dialogs.
     */
    private DialogXmlFactory accessDialogXmlFactory() {
        if (mDialogFactory instanceof DialogXmlFactory) {
            return (DialogXmlFactory) mDialogFactory;
        }
        if (mDialogXmlFactory == null) {
            mDialogXmlFactory = new DialogXmlFactory(mContext);
        }
        return mDialogXmlFactory;
    }

    /**
     * Checks whether the current active network is at this time connected or not.
     *
     * @return {@code True} if active network is connected, {@code false} otherwise.
     * @see ConnectivityManager#getActiveNetworkInfo()
     * @see NetworkInfo#isConnected()
     * @see #isNetworkConnected(int)
     */
    @CheckResult
    public boolean isActiveNetworkConnected() {
        this.ensureConnectivityManager();
        final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
        return info != null && info.isConnected();
    }

    /**
     * Checks whether a network with the specified <var>networkType</var> is at this time connected
     * or no.
     *
     * @param networkType The desired network type to check for connection.
     * @return {@code True} if the requested network is connected, {@code false} otherwise.
     * @see ConnectivityManager#getNetworkInfo(int)
     * @see NetworkInfo#isConnected()
     */
    @CheckResult
    public boolean isNetworkConnected(int networkType) {
        this.ensureConnectivityManager();
        final NetworkInfo info = mConnectivityManager.getNetworkInfo(networkType);
        return info != null && info.isConnected();
    }

    /**
     * Ensures that the connectivity manager is initialized.
     */
    private void ensureConnectivityManager() {
        if (mConnectivityManager == null)
            this.mConnectivityManager = (ConnectivityManager) mContext
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
    }

    /**
     * Sets a boolean flag indicating whether a view hierarchy of the related context is created or not.
     *
     * @param created {@code True} if view hierarchy is created, {@code false} otherwise.
     * @see #isViewCreated()
     */
    public void setViewCreated(boolean created) {
        this.updatePrivateFlags(PFLAG_VIEW_CREATED, created);
    }

    /**
     * Returns the boolean flag indicating whether view hierarchy of the related context is created
     * or not.
     *
     * @return {@code True} if view is created, {@code false} otherwise.
     * @see #setViewCreated(boolean)
     */
    public boolean isViewCreated() {
        return hasPrivateFlag(PFLAG_VIEW_CREATED);
    }

    /**
     * Sets a boolean flag indicating whether the related context has been paused or not.
     *
     * @param paused {@code True} if context is paused, {@code false} otherwise.
     */
    public void setPaused(boolean paused) {
        this.updatePrivateFlags(PFLAG_PAUSED, paused);
    }

    /**
     * Returns the boolean flag indicating whether the related context is paused or not.
     *
     * @return {@code True} if context is paused, {@code false} otherwise.
     */
    public boolean isPaused() {
        return hasPrivateFlag(PFLAG_PAUSED);
    }

    /**
     * Adds a request with the specified <var>request</var> flag into the registered ones.
     *
     * @param request The request flag that should be registered.
     * @see #isRequestRegistered(int)
     * @see #unregisterRequest(int)
     */
    public void registerRequest(int request) {
        this.mRequestFlags |= request;
    }

    /**
     * Removes request with the specified <var>request</var> flag from the registered ones.
     *
     * @param request The request flag that should be unregistered.
     * @see #registerRequest(int)
     * @see #isRequestRegistered(int)
     */
    public void unregisterRequest(int request) {
        this.mRequestFlags &= ~request;
    }

    /**
     * Checks whether a request with the specified <var>request</var> flag is registered or not.
     *
     * @param request The request flag for which to check if it is registered.
     * @return {@code True} if request is registered, {@code false} otherwise.
     * @see #registerRequest(int)
     * @see #unregisterRequest(int)
     */
    public boolean isRequestRegistered(int request) {
        return (mRequestFlags & request) != 0;
    }

    /**
     * Updates the current private flags.
     *
     * @param flag Value of the desired flag to add/remove to/from the current private flags.
     * @param add  Boolean flag indicating whether to add or remove the specified <var>flag</var>.
     */
    @SuppressWarnings("unused")
    private void updatePrivateFlags(int flag, boolean add) {
        if (add)
            this.mPrivateFlags |= flag;
        else
            this.mPrivateFlags &= ~flag;
    }

    /**
     * Returns a boolean flag indicating whether the specified <var>flag</var> is contained within
     * the current private flags or not.
     *
     * @param flag Value of the flag to check.
     * @return {@code True} if the requested flag is contained, {@code false} otherwise.
     */
    @SuppressWarnings("unused")
    private boolean hasPrivateFlag(int flag) {
        return (mPrivateFlags & flag) != 0;
    }

    /**
     * Inner classes ===============================================================================
     */
}