com.google.android.apps.muzei.featuredart.FeaturedArtSource.java Source code

Java tutorial

Introduction

Here is the source code for com.google.android.apps.muzei.featuredart.FeaturedArtSource.java

Source

/*
 * Copyright 2014 Google Inc.
 *
 * 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.google.android.apps.muzei.featuredart;

import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.widget.Toast;

import com.google.android.apps.muzei.api.Artwork;
import com.google.android.apps.muzei.api.RemoteMuzeiArtSource;
import com.google.android.apps.muzei.api.UserCommand;
import com.google.android.apps.muzei.util.IOUtil;
import com.google.android.apps.muzei.util.LogUtil;

import net.nurik.roman.muzei.BuildConfig;
import net.nurik.roman.muzei.R;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.TimeZone;

import static com.google.android.apps.muzei.util.LogUtil.LOGD;
import static com.google.android.apps.muzei.util.LogUtil.LOGE;
import static com.google.android.apps.muzei.util.LogUtil.LOGW;

public class FeaturedArtSource extends RemoteMuzeiArtSource {
    private static final String TAG = LogUtil.makeLogTag(FeaturedArtSource.class);
    private static final String SOURCE_NAME = "FeaturedArt";

    private static final String QUERY_URL = "http://muzeiapi.appspot.com/featured?cachebust=1";

    private static final int COMMAND_ID_SHARE = 1;
    private static final int COMMAND_ID_DEBUG_INFO = 51;

    private static final int MAX_JITTER_MILLIS = 20 * 60 * 1000;

    private static Random sRandom = new Random();

    private static final SimpleDateFormat sDateFormatTZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
    private static final SimpleDateFormat sDateFormatLocal = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    static {
        sDateFormatTZ.setTimeZone(TimeZone.getTimeZone("UTC"));
    }

    public FeaturedArtSource() {
        super(SOURCE_NAME);
    }

    @Override
    protected void onUpdate(int reason) {
        List<UserCommand> commands = new ArrayList<UserCommand>();
        if (reason == UPDATE_REASON_INITIAL) {
            // Show initial photo (starry night)
            publishArtwork(new Artwork.Builder().imageUri(Uri.parse("file:///android_asset/starrynight.jpg"))
                    .title("The Starry Night").token("initial")
                    .byline("Vincent van Gogh, 1889.\nMuzei shows a new painting every day.")
                    .viewIntent(new Intent(Intent.ACTION_VIEW,
                            Uri.parse("http://www.wikipaintings.org/en/vincent-van-gogh/the-starry-night-1889")))
                    .build());
            commands.add(new UserCommand(BUILTIN_COMMAND_ID_NEXT_ARTWORK));
            // show the latest photo in 15 minutes
            scheduleUpdate(System.currentTimeMillis() + 15 * 60 * 1000);

        } else {
            // For everything but the initial update, defer to RemoteMuzeiArtSource
            super.onUpdate(reason);
        }

        commands.add(new UserCommand(COMMAND_ID_SHARE, getString(R.string.action_share_artwork)));
        if (BuildConfig.DEBUG) {
            commands.add(new UserCommand(COMMAND_ID_DEBUG_INFO, "Debug info"));
        }
        setUserCommands(commands);
    }

    @Override
    protected void onSubscriberAdded(ComponentName subscriber) {
        super.onSubscriberAdded(subscriber);
        Artwork currentArtwork = getCurrentArtwork();
        if (currentArtwork != null && !"initial".equals(currentArtwork.getToken())) {
            // TODO: is this really necessary?
            // When a subscriber is added, manually try a fetch, unless this is the
            // first update
            onUpdate(UPDATE_REASON_OTHER);
        }
    }

    @Override
    protected void onCustomCommand(int id) {
        super.onCustomCommand(id);
        if (COMMAND_ID_SHARE == id) {
            Artwork currentArtwork = getCurrentArtwork();
            if (currentArtwork == null) {
                LOGW(TAG, "No current artwork, can't share.");
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(FeaturedArtSource.this,
                                R.string.featuredart_source_error_no_artwork_to_share, Toast.LENGTH_SHORT).show();
                    }
                });
                return;
            }

            String detailUrl = ("initial".equals(currentArtwork.getToken()))
                    ? "http://www.wikipaintings.org/en/vincent-van-gogh/the-starry-night-1889"
                    : currentArtwork.getViewIntent().getDataString();
            String artist = currentArtwork.getByline().replaceFirst("\\.\\s*($|\\n).*", "").trim();

            Intent shareIntent = new Intent(Intent.ACTION_SEND);
            shareIntent.setType("text/plain");
            shareIntent.putExtra(Intent.EXTRA_TEXT, "My Android wallpaper today is '"
                    + currentArtwork.getTitle().trim() + "' by " + artist + ". #MuzeiFeaturedArt\n\n" + detailUrl);
            shareIntent = Intent.createChooser(shareIntent, "Share artwork");
            shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(shareIntent);

        } else if (COMMAND_ID_DEBUG_INFO == id) {
            long nextUpdateTimeMillis = getSharedPreferences().getLong("scheduled_update_time_millis", 0);
            final String nextUpdateTime;
            if (nextUpdateTimeMillis > 0) {
                Date d = new Date(nextUpdateTimeMillis);
                nextUpdateTime = SimpleDateFormat.getDateTimeInstance().format(d);
            } else {
                nextUpdateTime = "None";
            }

            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(FeaturedArtSource.this, "Next update time: " + nextUpdateTime, Toast.LENGTH_LONG)
                            .show();
                }
            });
        }
    }

    @Override
    protected void onTryUpdate(int reason) throws RetryException {
        Artwork currentArtwork = getCurrentArtwork();
        Artwork artwork;
        JSONObject jsonObject;
        try {
            jsonObject = IOUtil.fetchJsonObject(QUERY_URL);
            artwork = Artwork.fromJson(jsonObject);
        } catch (JSONException e) {
            LOGE(TAG, "Error reading JSON", e);
            throw new RetryException(e);
        } catch (IOException e) {
            LOGE(TAG, "Error reading JSON", e);
            throw new RetryException(e);
        }

        if (artwork != null && currentArtwork != null && artwork.getImageUri() != null
                && artwork.getImageUri().equals(currentArtwork.getImageUri())) {
            LOGD(TAG, "Skipping update of same artwork.");
        } else {
            LOGD(TAG, "Publishing artwork update: " + artwork);
            if (artwork != null && jsonObject != null) {
                publishArtwork(artwork);
            }
        }

        Date nextTime = null;
        String nextTimeStr = jsonObject.optString("nextTime");
        if (!TextUtils.isEmpty(nextTimeStr)) {
            int len = nextTimeStr.length();
            if (len > 4 && nextTimeStr.charAt(len - 3) == ':') {
                nextTimeStr = nextTimeStr.substring(0, len - 3) + nextTimeStr.substring(len - 2);
            }
            try {
                nextTime = sDateFormatTZ.parse(nextTimeStr);
            } catch (ParseException ignored) {
                try {
                    sDateFormatLocal.setTimeZone(TimeZone.getDefault());
                    nextTime = sDateFormatLocal.parse(nextTimeStr);
                } catch (ParseException e) {
                    LOGE(TAG, "Can't schedule update; " + "invalid date format '" + nextTimeStr + "'", e);
                }
            }
        }

        boolean scheduleFallback = true;
        if (nextTime != null) {
            // jitter by up to N milliseconds
            scheduleUpdate(nextTime.getTime() + sRandom.nextInt(MAX_JITTER_MILLIS));
            scheduleFallback = false;
        }

        if (scheduleFallback) {
            // No next time, default to checking in 12 hours
            scheduleUpdate(System.currentTimeMillis() + 12 * 60 * 60 * 1000);
        }
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (BuildConfig.DEBUG && intent != null && "demoartwork".equals(intent.getAction())) {
            publishArtwork(new Artwork.Builder().imageUri(Uri.parse(intent.getStringExtra("image")))
                    .title(intent.getStringExtra("title")).token(intent.getStringExtra("image"))
                    .byline(intent.getStringExtra("byline"))
                    .viewIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(intent.getStringExtra("details"))))
                    .build());
            removeAllUserCommands();
        }

        super.onHandleIntent(intent);
    }
}