com.linkbubble.util.YouTubeEmbedHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.linkbubble.util.YouTubeEmbedHelper.java

Source

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package com.linkbubble.util;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ResolveInfo;
import android.net.ConnectivityManager;
import android.os.AsyncTask;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.linkbubble.Config;
import com.linkbubble.ConfigAPIs;
import com.linkbubble.MainApplication;
import com.linkbubble.MainController;
import com.linkbubble.R;
import com.linkbubble.Settings;
import com.squareup.picasso.Picasso;

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

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class YouTubeEmbedHelper {

    private Context mContext;
    private List<String> mEmbedIds = new ArrayList<String>();

    private static class EmbedInfo {
        String mTitle;
        String mThumbnailUrl;
        String mId;
    }

    private List<EmbedInfo> mEmbedInfo = new ArrayList<EmbedInfo>();
    private DownloadYouTubeEmbedInfoTask mCurrentDownloadTask;

    public ResolveInfo mYouTubeResolveInfo;

    public YouTubeEmbedHelper(Context context) {
        mContext = context;
        mYouTubeResolveInfo = Settings.get().getYouTubeViewResolveInfo();
    }

    public void clear() {
        mEmbedIds.clear();
        if (mCurrentDownloadTask != null) {
            synchronized (mCurrentDownloadTask) {
                if (mCurrentDownloadTask != null) {
                    mCurrentDownloadTask.cancel(true);
                }
                mCurrentDownloadTask = null;
            }
        }
    }

    public int size() {
        return mEmbedIds.size();
    }

    /*
     * Known YouTube embed URLs:
    * http://www.youtube.com/embed/oSAW1tSNIa4?version=3&rel=1&fs=1&showsearch=0&showinfo=1&iv_load_policy=1&wmode=transparent
    * https://www.youtube.com/embed/q1dpQKntj_w
     */
    public boolean onEmbeds(String[] strings) {
        if (strings == null || strings.length == 0) {
            return false;
        }

        boolean listChanged = false;

        for (String string : strings) {
            int prefixStartIndex = string.indexOf(Config.YOUTUBE_EMBED_PREFIX);
            if (prefixStartIndex > -1) {
                URL url;
                try {
                    url = new URL(string);
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                    break;
                }

                String path = url.getPath();
                int pathStartIndex = path.indexOf(Config.YOUTUBE_EMBED_PATH_SUFFIX);
                if (pathStartIndex > -1) {
                    String videoId = path.substring(pathStartIndex + Config.YOUTUBE_EMBED_PATH_SUFFIX.length());
                    if (videoId.length() > 0) {
                        boolean onList = false;
                        if (mEmbedIds.size() > 0) {
                            for (String s : mEmbedIds) {
                                if (s.equals(videoId)) {
                                    onList = true;
                                    break;
                                }
                            }
                        }
                        if (onList == false) {
                            mEmbedIds.add(videoId);
                            listChanged = true;
                        }
                    }
                }
            }
        }

        if (listChanged) {
            if (mCurrentDownloadTask != null) {
                synchronized (mCurrentDownloadTask) {
                    if (mCurrentDownloadTask != null) {
                        mCurrentDownloadTask.cancel(true);
                    }
                    mCurrentDownloadTask = new DownloadYouTubeEmbedInfoTask(false, null);
                    mCurrentDownloadTask.execute(null, null, null);
                }
            } else {
                mCurrentDownloadTask = new DownloadYouTubeEmbedInfoTask(false, null);
                mCurrentDownloadTask.execute(null, null, null);
            }
        }

        return mEmbedIds.size() > 0;
    }

    private boolean loadYouTubeVideo(String id) {
        if (mYouTubeResolveInfo != null) {
            if (MainApplication.loadIntent(mContext, mYouTubeResolveInfo.activityInfo.packageName,
                    mYouTubeResolveInfo.activityInfo.name, Config.YOUTUBE_WATCH_PREFIX + id, -1, true)) {
                // L_WATCH: L currently lacks getRecentTasks(), so minimize here
                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
                    MainController.get().switchToBubbleView(false);
                }
                return true;
            }
        }

        return false;
    }

    public boolean onOpenInAppButtonClick() {
        int size = mEmbedIds.size();
        if (size == 1) {
            return loadYouTubeVideo(mEmbedIds.get(0));
        } else if (size > 1) {
            Util.showThemedDialog(getMultipleEmbedsDialog());
            return true;
        }

        return false;
    }

    private boolean embedInfoMatchesIds() {
        if (mEmbedIds.size() == mEmbedInfo.size()) {
            for (String id : mEmbedIds) {
                boolean found = false;
                for (EmbedInfo info : mEmbedInfo) {
                    if (info.mId.equals(id)) {
                        found = true;
                        break;
                    }
                }

                if (found == false) {
                    return false;
                }
            }

            return true;
        }

        return false;
    }

    private AlertDialog getMultipleEmbedsDialog() {
        if (embedInfoMatchesIds()) {
            return getEmbedResultsDialog();
        } else {
            AlertDialog.Builder builder = new AlertDialog.Builder(mContext);

            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view = inflater.inflate(R.layout.view_loading, null);

            TextView textView = (TextView) view.findViewById(R.id.loading_text);
            textView.setText(R.string.loading_youtube_embed_info);

            builder.setView(view);
            builder.setIcon(0);

            AlertDialog alertDialog = builder.create();
            alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

            if (mCurrentDownloadTask != null) {
                synchronized (mCurrentDownloadTask) {
                    if (mCurrentDownloadTask != null) {
                        mCurrentDownloadTask.cancel(true);
                    }
                    mCurrentDownloadTask = new DownloadYouTubeEmbedInfoTask(true, alertDialog);
                    mCurrentDownloadTask.execute(null, null, null);
                }
            } else {
                mCurrentDownloadTask = new DownloadYouTubeEmbedInfoTask(true, alertDialog);
                mCurrentDownloadTask.execute(null, null, null);
            }

            return alertDialog;
        }
    }

    AlertDialog getEmbedResultsDialog() {
        if (mEmbedInfo.size() > 0) {
            ListView listView = new ListView(mContext);
            listView.setAdapter(new EmbedItemAdapter());

            AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
            builder.setView(listView);
            builder.setIcon(mYouTubeResolveInfo.loadIcon(mContext.getPackageManager()));
            builder.setTitle(R.string.title_youtube_embed_to_load);

            final AlertDialog alertDialog = builder.create();
            alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    EmbedInfo embedInfo = (EmbedInfo) view.getTag();
                    if (embedInfo != null) {
                        loadYouTubeVideo(embedInfo.mId);
                    }
                    alertDialog.dismiss();
                }
            });

            return alertDialog;
        } else {
            final AlertDialog alertDialog = new AlertDialog.Builder(mContext).create();
            alertDialog.setTitle(R.string.youtube_embed_error_title);
            alertDialog.setMessage(mContext.getString(R.string.youtube_embed_error_summary));
            alertDialog.setButton(AlertDialog.BUTTON_POSITIVE,
                    mContext.getResources().getString(R.string.action_ok), new DialogInterface.OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            alertDialog.dismiss();
                        }

                    });
            alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
            return alertDialog;
        }
    }

    private class DownloadYouTubeEmbedInfoTask extends AsyncTask<Void, Void, Boolean> {
        private AlertDialog mLoadingAlertDialog;
        private boolean mShowResultsOnCompletion;

        DownloadYouTubeEmbedInfoTask(boolean showResultsOnCompletion, AlertDialog loadingAlertDialog) {
            super();
            mShowResultsOnCompletion = showResultsOnCompletion;
            mLoadingAlertDialog = loadingAlertDialog;
        }

        protected Boolean doInBackground(Void... arg) {

            // This only should happen on a page change, in which case, abort
            if (mEmbedIds.size() == 0 || isCancelled()) {
                return false;
            }

            if (mCurrentDownloadTask != null) {
                synchronized (mCurrentDownloadTask) {
                    if (mCurrentDownloadTask != this) {
                        return false;
                    }
                }
            }

            String idsAsString = "";
            for (String id : mEmbedIds) {
                if (idsAsString.length() > 0) {
                    idsAsString += ",";
                }
                idsAsString += id;
            }

            ConnectivityManager connectivityManager = (ConnectivityManager) mContext
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            String thumbnailsArg;
            if (Config.isLowMemoryDevice() || connectivityManager.isActiveNetworkMetered()
                    || NetworkConnectivity.isConnectedFast(mContext) == false) {
                thumbnailsArg = Config.YOUTUBE_API_THUMBNAILS_LOW_QUALITY;
            } else {
                thumbnailsArg = Config.YOUTUBE_API_THUMBNAILS_HIGH_QUALITY;
            }

            String url = "https://www.googleapis.com/youtube/v3/videos?id=" + idsAsString + "&key="
                    + ConfigAPIs.YOUTUBE_API_KEY + "&part=snippet&fields=items(id,snippet(title," + thumbnailsArg
                    + "))";

            mEmbedInfo.clear();
            String jsonAsString = Util.downloadJSONAsString(url, 5000);
            if (jsonAsString != null) {
                try {
                    JSONObject jsonObject = new JSONObject(jsonAsString);
                    Object itemsObject = jsonObject.get("items");
                    if (itemsObject instanceof JSONArray) {
                        JSONArray jsonArray = (JSONArray) itemsObject;
                        for (int i = 0; i < jsonArray.length(); ++i) {
                            JSONObject item = jsonArray.getJSONObject(i);
                            EmbedInfo embedInfo = new EmbedInfo();
                            embedInfo.mId = item.getString("id");
                            JSONObject snippet = item.getJSONObject("snippet");
                            if (snippet != null) {
                                embedInfo.mTitle = snippet.getString("title");
                                JSONObject thumbnails = snippet.getJSONObject("thumbnails");
                                if (thumbnails != null) {
                                    try {
                                        JSONObject mediumEntry = thumbnails.getJSONObject("medium");
                                        if (mediumEntry != null) {
                                            embedInfo.mThumbnailUrl = mediumEntry.getString("url");
                                            mEmbedInfo.add(embedInfo);
                                        }
                                    } catch (JSONException e) {
                                        // ignore "org.json.JSONException: No value for medium"
                                    }

                                    // Fallback to checking for default...
                                    if (embedInfo.mThumbnailUrl == null) {
                                        JSONObject defaultEntry = thumbnails.getJSONObject("default");
                                        if (defaultEntry != null) {
                                            embedInfo.mThumbnailUrl = defaultEntry.getString("url");
                                            mEmbedInfo.add(embedInfo);
                                        }
                                    }
                                }
                            }
                        }
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            if (mCurrentDownloadTask != null) {
                synchronized (mCurrentDownloadTask) {
                    if (mCurrentDownloadTask != this) {
                        return false;
                    }
                }
            }

            if (isCancelled()) {
                return false;
            }

            return mEmbedInfo.size() > 0 ? true : false;
        }

        protected void onPostExecute(Boolean result) {
            if (result.booleanValue() == true && mShowResultsOnCompletion && isCancelled() == false) {
                mLoadingAlertDialog.dismiss();
                mLoadingAlertDialog = null;

                Util.showThemedDialog(getEmbedResultsDialog());
            }
        }
    }

    private class EmbedItemAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return mEmbedInfo.size();
        }

        @Override
        public Object getItem(int position) {
            return mEmbedInfo.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            if (convertView == null) {
                LayoutInflater inflater = (LayoutInflater) mContext
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(R.layout.view_youtube_embed_item, null);
            }

            EmbedInfo embedInfo = mEmbedInfo.get(position);

            ImageView imageView = (ImageView) convertView.findViewById(R.id.image);
            if (embedInfo.mThumbnailUrl != null) {
                Picasso.with(mContext).load(embedInfo.mThumbnailUrl).into(imageView);
            }

            TextView textView = (TextView) convertView.findViewById(R.id.text);
            textView.setText(embedInfo.mTitle);

            convertView.setTag(embedInfo);

            return convertView;
        }
    }
}