com.luongbui.andersenfestival.muzei.AndersenFestivalSource.java Source code

Java tutorial

Introduction

Here is the source code for com.luongbui.andersenfestival.muzei.AndersenFestivalSource.java

Source

/*******************************************************************************
 * Copyright 2014 Manh Luong   Bui
 * 
 * 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 com.luongbui.andersenfestival.muzei;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.TreeSet;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.support.v4.content.FileProvider;

import com.google.android.apps.muzei.api.Artwork;
import com.google.android.apps.muzei.api.MuzeiArtSource;
import com.luongbui.andersenfestival.muzei.model.ArtPiece;

public class AndersenFestivalSource extends MuzeiArtSource {

    private static final String FILE_PROVIDER_AUTHORITIES = "com.luongbui.andersenfestival.muzei.fileprovider";

    private static final String PORTRAITS_SUBDIR = "andersen_portraits_2014";

    private static final String NAME = "luongbui.AndersenFestivalSource";

    private static final String SUBS_KEY = NAME + ".Subs";

    private static final String ART_INDEX_KEY = NAME + ".Index";

    private static final int NO_INDEX_CODE = -1;

    /**
     * public and static to use it as data for the list adapter of the configuration activity.<br>
     * <br>
     * A bit brutal, I know, but it's a quick & dirty solution.
     */
    public static final ArtPiece[] PORTRAITS = {
            new ArtPiece("giorgia_marras.jpg", "Hans Christian Andersen", "Giorgia Marras", "2014",
                    "http://giorgiamarras.blogspot.it/"),
            new ArtPiece("bruno_zocca.jpg", "Hans Christian Andersen", "Bruno Zocca", "2014",
                    "http://brunozoccaillustrator.tumblr.com/"),
            new ArtPiece("luca_tagliafico.jpg", "Hans Christian Andersen", "Luca Tagliafico", "2014",
                    "http://lucatagliaficoillustrator.tumblr.com/"),
            new ArtPiece("arianna_zuppello.jpg", "Hans Christian Andersen", "Arianna Zuppello", "2014",
                    "http://arianna-zuppello.tumblr.com/"),
            new ArtPiece("daniele_castellano.jpg", "Hans Christian Andersen", "Daniele Castellano", "2014",
                    "http://altairiv.tumblr.com/"),
            new ArtPiece("letizia_iannaccone.jpg", "Hans Christian Andersen", "Letizia Iannaccone", "2014",
                    "http://www.letiziaiannaccone.com/"),
            new ArtPiece("jacopo_oliveri.jpg", "Hans Christian Andersen", "Jacopo Oliveri", "2014",
                    "http://www.fatomale.com/"),
            new ArtPiece("stefano_tirasso.jpg", "Hans Christian Andersen", "Stefano Tirasso", "2014",
                    "http://stetirasso.tumblr.com/"),
            new ArtPiece("matilde_martinelli.jpg", "Hans Christian Andersen", "Matilde Martinelli", "2014",
                    "http://matildemartinelli.tumblr.com/"),
            new ArtPiece("olga_tranchini.jpg", "Hans Christian Andersen", "Olga Tranchini", "2014",
                    "http://olgatranchini.tumblr.com/"),
            new ArtPiece("anais_tonelli.jpg", "Hans Christian Andersen", "Anais Tonelli", "2014",
                    "http://anaistonelli.blogspot.it/"),
            new ArtPiece("silvia_venturi.jpg", "Hans Christian Andersen", "Silvia Venturi", "2014",
                    "http://silviaventuri.tumblr.com/"),
            new ArtPiece("marco_bassi.jpg", "Hans Christian Andersen", "Marco Bassi", "2014",
                    "http://www.fareunapausa.com/"),
            new ArtPiece("francesca_consalvo.jpg", "Hans Christian Andersen", "Francesca Consalvo", "2014",
                    "about:blank") };

    private SharedPreferences prefs;

    private Uri fileUri;

    public AndersenFestivalSource() {
        super(NAME);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        prefs = getApplicationContext().getSharedPreferences(NAME, Context.MODE_PRIVATE);
        setUserCommands(BUILTIN_COMMAND_ID_NEXT_ARTWORK);
    }

    @Override
    protected void onSubscriberAdded(ComponentName subscriber) {
        super.onSubscriberAdded(subscriber);
        //android.util.Log.d("onSubscriberAdded()", "onSubscriberAdded()");
        // Add the subscriber, so we can grant permissions later.
        Set<String> subs = prefs.getStringSet(SUBS_KEY, new TreeSet<String>());
        subs.add(subscriber.getPackageName());
        saveSubsPrefs(subs);
    }

    @Override
    protected void onSubscriberRemoved(ComponentName subscriber) {
        super.onSubscriberRemoved(subscriber);
        //android.util.Log.d("onSubscriberRemoved()", "onSubscriberRemoved()");
        // Remove the subscriber.
        Set<String> subs = prefs.getStringSet(SUBS_KEY, new TreeSet<String>());
        subs.remove(subscriber.getPackageName());
        saveSubsPrefs(subs);
    }

    private void saveSubsPrefs(Set<String> subs) {
        SharedPreferences.Editor editor = prefs.edit();
        editor.putStringSet(SUBS_KEY, subs);
        editor.commit();
    }

    private int loadArtIndex() {
        int res = prefs.getInt(ART_INDEX_KEY, NO_INDEX_CODE);
        if (res == NO_INDEX_CODE) {
            res = (int) (Math.random() * ((AndersenFestivalSource.PORTRAITS.length - 1) + 1));
            saveArtIndex(res);
        }
        return res;
    }

    private int incrArtIndex(int artIndex) {
        if (artIndex < (AndersenFestivalSource.PORTRAITS.length - 1))
            artIndex++;
        else
            artIndex = 0;
        saveArtIndex(artIndex);
        return artIndex;
    }

    private void saveArtIndex(int value) {
        SharedPreferences.Editor editor = prefs.edit();
        editor.putInt(ART_INDEX_KEY, value);
        editor.commit();
    }

    @Override
    protected void onUpdate(int reason) {
        try {
            int artIndex = loadArtIndex(); // Random if none exists.
            //android.util.Log.d("INDEX", ""+artIndex);
            if (reason == UPDATE_REASON_USER_NEXT || reason == UPDATE_REASON_SCHEDULED) {
                artIndex = incrArtIndex(artIndex);
                //android.util.Log.d("INDEX USER NEXT", ""+artIndex);
            }
            //For now, empty the external sub dir each time: TODO a more "flexible" cache system.
            deleteExternalSubdir(new File(getApplicationContext().getFilesDir(), PORTRAITS_SUBDIR));
            File outFile = new File(getApplicationContext().getFilesDir(),
                    PORTRAITS_SUBDIR + File.separator + PORTRAITS[artIndex].getFileName());
            //TODO test if the file exits, should be false.
            //android.util.Log.d("TEST FILE EXISTS", ""+outFile.exists()+" : " + outFile.getPath());
            copyAsset(PORTRAITS_SUBDIR, PORTRAITS[artIndex].getFileName());
            //TODO test if the file exits, should be true.
            //android.util.Log.d("TEST FILE EXISTS", ""+outFile.exists()+" : " + outFile.getPath());
            fileUri = FileProvider.getUriForFile(getApplicationContext(), FILE_PROVIDER_AUTHORITIES, outFile);
            Set<String> subscribers = prefs.getStringSet(SUBS_KEY, new TreeSet<String>());
            for (String subPackage : subscribers)
                getApplicationContext().grantUriPermission(subPackage, fileUri,
                        Intent.FLAG_GRANT_READ_URI_PERMISSION);
            //android.util.Log.d("SHARED FILE URI", ""+fileUri.toString());
            publishArtwork(new Artwork.Builder().imageUri(fileUri).title(PORTRAITS[artIndex].getTitle())
                    .byline(PORTRAITS[artIndex].getByLine())
                    .viewIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(PORTRAITS[artIndex].getAuthorUrl())))
                    .build());
            // 12 Hours
            scheduleUpdate(System.currentTimeMillis() + 12 * 60 * 60 * 1000);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    protected void deleteExternalSubdir(File subPath) {
        if (subPath.isDirectory()) {
            for (File child : subPath.listFiles())
                deleteExternalSubdir(child);
        }
        subPath.delete();
    }

    /**
     * Copy a single asset to private app folder.<br>
     * <br>
     * It creates the sub folder accordingly.
     * <br>
     * @param subPath A relative path within the assets. Can be a directory: "andersen_portraits".
     * @param fileName Name of file to copy, relative to subPath.
     * @throws IOException
     */
    protected void copyAsset(String subPath, String fileName) throws IOException {
        android.content.res.AssetManager assetManager = getAssets();
        File outDir = new File(getApplicationContext().getFilesDir(), subPath);
        if (!outDir.exists())
            outDir.mkdir();
        // Copy the asset.
        copyFileToDataDir(assetManager, subPath + File.separator + fileName);
    }

    /**
     * Copy the file using the asset manager.<br>
     * 
     * @param assetManager
     * @param fileName Relative to assets folder.
     * @throws IOException
     */
    protected void copyFileToDataDir(android.content.res.AssetManager assetManager, String fileName)
            throws IOException {
        // Open the asset file.
        InputStream in = assetManager.open(fileName);
        // Open the target file.
        File outFile = new File(getApplicationContext().getFilesDir(), fileName);
        OutputStream out = new FileOutputStream(outFile);
        // Actual copy.
        streamCopy(in, out);
        // Close everything.
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
    }

    /**
     * Copy from in stream to out stream.
     * 
     * @param in
     * @param out
     * @throws IOException
     */
    protected void streamCopy(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
        int read;
        for (; (read = in.read(buffer)) != -1;)
            out.write(buffer, 0, read);
    }

}