/* 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;
}
}
}