Java tutorial
/* * Copyright (c) 2013 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.yydw; import android.accounts.AccountManager; import android.app.Activity; import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; import android.provider.MediaStore; import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.android.volley.toolbox.ImageLoader; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.api.client.extensions.android.http.AndroidHttp; import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; import com.google.api.client.googleapis.extensions.android.gms.auth.GooglePlayServicesAvailabilityIOException; import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; import com.google.api.client.http.HttpTransport; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.gson.GsonFactory; import com.google.api.client.util.ExponentialBackOff; import com.google.api.services.youtube.YouTube; import com.google.api.services.youtube.model.ChannelListResponse; import com.google.api.services.youtube.model.PlaylistItem; import com.google.api.services.youtube.model.PlaylistItemListResponse; import com.google.api.services.youtube.model.Video; import com.google.api.services.youtube.model.VideoListResponse; import com.google.api.services.youtube.model.VideoSnippet; import com.google.yydw.util.NetworkSingleton; import com.google.yydw.util.Upload; import com.google.yydw.util.Utils; import com.google.yydw.util.VideoData; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * @author Ibrahim Ulukaya <ulukaya@google.com> * <p/> * Main activity class which handles authorization and intents. */ public class MainActivity extends Activity implements UploadsListFragment.Callbacks { // private static final int MEDIA_TYPE_VIDEO = 7; public static final String ACCOUNT_KEY = "accountName"; public static final String MESSAGE_KEY = "message"; public static final String YOUTUBE_ID = "youtubeId"; public static final String YOUTUBE_WATCH_URL_PREFIX = "http://www.youtube.com/watch?v="; static final String REQUEST_AUTHORIZATION_INTENT = "com.google.example.yt.RequestAuth"; static final String REQUEST_AUTHORIZATION_INTENT_PARAM = "com.google.example.yt.RequestAuth.param"; private static final int REQUEST_GOOGLE_PLAY_SERVICES = 0; private static final int REQUEST_GMS_ERROR_DIALOG = 1; private static final int REQUEST_ACCOUNT_PICKER = 2; private static final int REQUEST_AUTHORIZATION = 3; private static final int RESULT_PICK_IMAGE_CROP = 4; private static final int RESULT_VIDEO_CAP = 5; private static final int REQUEST_DIRECT_TAG = 6; private static final String TAG = "MainActivity"; final HttpTransport transport = AndroidHttp.newCompatibleTransport(); final JsonFactory jsonFactory = new GsonFactory(); GoogleAccountCredential credential; private ImageLoader mImageLoader; private String mChosenAccountName; private Uri mFileURI = null; private VideoData mVideoData; private UploadBroadcastReceiver broadcastReceiver; private UploadsListFragment mUploadsListFragment; @Override protected void onCreate(Bundle savedInstanceState) { getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS); super.onCreate(savedInstanceState); mUploadsListFragment = new UploadsListFragment(getApplicationContext()); // Check to see if the proper keys and playlist IDs have been set up if (!isCorrectlyConfigured()) { setContentView(R.layout.developer_setup_required); showMissingConfigurations(); } else { setContentView(R.layout.activity_main); ensureLoader(); credential = GoogleAccountCredential.usingOAuth2(getApplicationContext(), Arrays.asList(Auth.SCOPES)); // set exponential backoff policy credential.setBackOff(new ExponentialBackOff()); if (savedInstanceState != null) { mChosenAccountName = savedInstanceState.getString(ACCOUNT_KEY); } else { loadAccount(); } credential.setSelectedAccountName(mChosenAccountName); mUploadsListFragment = (UploadsListFragment) getFragmentManager().findFragmentById(R.id.list_fragment); } } /** * This method checks various internal states to figure out at startup time * whether certain elements have been configured correctly by the developer. * Checks that: * <ul> * <li>the API key has been configured</li> * <li>the playlist ID has been configured</li> * </ul> * * @return true if the application is correctly configured for use, false if * not */ private boolean isCorrectlyConfigured() { // This isn't going to internationalize well, but we only really need // this for the sample app. // Real applications will remove this section of code and ensure that // all of these values are configured. if (Auth.KEY.startsWith("Replace")) { return false; } if (Constants.UPLOAD_PLAYLIST.startsWith("Replace")) { return false; } return true; } /** * This method renders the ListView explaining what the configurations the * developer of this application has to complete. Typically, these are * static variables defined in {@link Auth} and {@link Constants}. */ private void showMissingConfigurations() { List<MissingConfig> missingConfigs = new ArrayList<MissingConfig>(); // Make sure an API key is registered if (Auth.KEY.startsWith("Replace")) { missingConfigs.add(new MissingConfig("API key not configured", "KEY constant in Auth.java must be configured with your Simple API key from the Google API Console")); } // Make sure a playlist ID is registered if (Constants.UPLOAD_PLAYLIST.startsWith("Replace")) { missingConfigs.add(new MissingConfig("Playlist ID not configured", "UPLOAD_PLAYLIST constant in Constants.java must be configured with a Playlist ID to submit to. (The playlist ID typically has a prexix of PL)")); } // Renders a simple_list_item_2, which consists of a title and a body // element ListAdapter adapter = new ArrayAdapter<MissingConfig>(this, android.R.layout.simple_list_item_2, missingConfigs) { @Override public View getView(int position, View convertView, ViewGroup parent) { View row; if (convertView == null) { LayoutInflater inflater = (LayoutInflater) getApplicationContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); row = inflater.inflate(android.R.layout.simple_list_item_2, null); } else { row = convertView; } TextView titleView = (TextView) row.findViewById(android.R.id.text1); TextView bodyView = (TextView) row.findViewById(android.R.id.text2); MissingConfig config = getItem(position); titleView.setText(config.title); bodyView.setText(config.body); return row; } }; // Wire the data adapter up to the view ListView missingConfigList = (ListView) findViewById(R.id.missing_config_list); missingConfigList.setAdapter(adapter); } @Override protected void onResume() { super.onResume(); if (broadcastReceiver == null) broadcastReceiver = new UploadBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(REQUEST_AUTHORIZATION_INTENT); LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, intentFilter); } private void ensureLoader() { if (mImageLoader == null) { // Get the ImageLoader through your singleton class. mImageLoader = NetworkSingleton.getInstance(this).getImageLoader(); } } private void loadAccount() { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); mChosenAccountName = sp.getString(ACCOUNT_KEY, null); invalidateOptionsMenu(); } private void saveAccount() { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); sp.edit().putString(ACCOUNT_KEY, mChosenAccountName).commit(); } private void loadData() { if (mChosenAccountName == null) { return; } loadUploadedVideos(); } @Override protected void onPause() { super.onPause(); if (broadcastReceiver != null) { LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver); } if (isFinishing()) { // mHandler.removeCallbacksAndMessages(null); } } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.activity_main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_refresh: loadData(); break; case R.id.menu_accounts: chooseAccount(); return true; } return super.onOptionsItemSelected(item); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_GMS_ERROR_DIALOG: break; case RESULT_PICK_IMAGE_CROP: if (resultCode == RESULT_OK) { mFileURI = data.getData(); if (mFileURI != null) { Intent intent = new Intent(this, ReviewActivity.class); intent.setData(mFileURI); startActivity(intent); } } break; case RESULT_VIDEO_CAP: if (resultCode == RESULT_OK) { mFileURI = data.getData(); if (mFileURI != null) { Intent intent = new Intent(this, ReviewActivity.class); intent.setData(mFileURI); startActivity(intent); } } break; case REQUEST_GOOGLE_PLAY_SERVICES: if (resultCode == Activity.RESULT_OK) { haveGooglePlayServices(); } else { checkGooglePlayServicesAvailable(); } break; case REQUEST_AUTHORIZATION: if (resultCode != Activity.RESULT_OK) { chooseAccount(); } break; case REQUEST_ACCOUNT_PICKER: if (resultCode == Activity.RESULT_OK && data != null && data.getExtras() != null) { String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME); if (accountName != null) { mChosenAccountName = accountName; credential.setSelectedAccountName(accountName); saveAccount(); } } break; case REQUEST_DIRECT_TAG: if (resultCode == Activity.RESULT_OK && data != null && data.getExtras() != null) { String youtubeId = data.getStringExtra(YOUTUBE_ID); if (youtubeId.equals(mVideoData.getYouTubeId())) { directTag(mVideoData); } } break; } } private void directTag(final VideoData video) { final Video updateVideo = new Video(); VideoSnippet snippet = video.addTags(Arrays.asList(Constants.DEFAULT_KEYWORD, Upload.generateKeywordFromPlaylistId(Constants.UPLOAD_PLAYLIST))); updateVideo.setSnippet(snippet); updateVideo.setId(video.getYouTubeId()); new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... voids) { YouTube youtube = new YouTube.Builder(transport, jsonFactory, credential) .setApplicationName(Constants.APP_NAME).build(); try { youtube.videos().update("snippet", updateVideo).execute(); } catch (UserRecoverableAuthIOException e) { startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION); } catch (IOException e) { Log.e(TAG, e.getMessage()); } return null; } }.execute((Void) null); Toast.makeText(this, R.string.video_submitted_to_ytdl, Toast.LENGTH_LONG).show(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString(ACCOUNT_KEY, mChosenAccountName); } private void loadUploadedVideos() { if (mChosenAccountName == null) { return; } setProgressBarIndeterminateVisibility(true); new AsyncTask<Void, Void, List<VideoData>>() { @Override protected List<VideoData> doInBackground(Void... voids) { YouTube youtube = new YouTube.Builder(transport, jsonFactory, credential) .setApplicationName(Constants.APP_NAME).build(); try { /* * Now that the user is authenticated, the app makes a * channels list request to get the authenticated user's * channel. Returned with that data is the playlist id for * the uploaded videos. * https://developers.google.com/youtube * /v3/docs/channels/list */ ChannelListResponse clr = youtube.channels().list("contentDetails").setMine(true).execute(); // Get the user's uploads playlist's id from channel list // response String uploadsPlaylistId = clr.getItems().get(0).getContentDetails().getRelatedPlaylists() .getUploads(); List<VideoData> videos = new ArrayList<VideoData>(); // Get videos from user's upload playlist with a playlist // items list request PlaylistItemListResponse pilr = youtube.playlistItems().list("id,contentDetails") .setPlaylistId(uploadsPlaylistId).setMaxResults(20l).execute(); List<String> videoIds = new ArrayList<String>(); // Iterate over playlist item list response to get uploaded // videos' ids. for (PlaylistItem item : pilr.getItems()) { videoIds.add(item.getContentDetails().getVideoId()); } // Get details of uploaded videos with a videos list // request. VideoListResponse vlr = youtube.videos().list("id,snippet,status") .setId(TextUtils.join(",", videoIds)).execute(); // Add only the public videos to the local videos list. for (Video video : vlr.getItems()) { if ("public".equals(video.getStatus().getPrivacyStatus())) { VideoData videoData = new VideoData(); videoData.setVideo(video); videos.add(videoData); } } // Sort videos by title Collections.sort(videos, new Comparator<VideoData>() { @Override public int compare(VideoData videoData, VideoData videoData2) { return videoData.getTitle().compareTo(videoData2.getTitle()); } }); return videos; } catch (final GooglePlayServicesAvailabilityIOException availabilityException) { showGooglePlayServicesAvailabilityErrorDialog(availabilityException.getConnectionStatusCode()); } catch (UserRecoverableAuthIOException userRecoverableException) { startActivityForResult(userRecoverableException.getIntent(), REQUEST_AUTHORIZATION); } catch (IOException e) { Utils.logAndShow(MainActivity.this, Constants.APP_NAME, e); } return null; } @Override protected void onPostExecute(List<VideoData> videos) { setProgressBarIndeterminateVisibility(false); if (videos == null) { return; } mUploadsListFragment.setVideos(videos); } }.execute((Void) null); } @Override public void onBackPressed() { // if (mDirectFragment.popPlayerFromBackStack()) { // super.onBackPressed(); // } } @Override public ImageLoader onGetImageLoader() { ensureLoader(); return mImageLoader; } @Override public void onVideoSelected(VideoData video) { mVideoData = video; Intent intent = new Intent(this, PlayActivity.class); intent.putExtra(YOUTUBE_ID, video.getYouTubeId()); startActivityForResult(intent, REQUEST_DIRECT_TAG); } @Override public void onConnected(String connectedAccountName) { // Make API requests only when the user has successfully signed in. loadData(); } public void pickFile(View view) { Intent intent = new Intent(Intent.ACTION_PICK); intent.setType("video/*"); startActivityForResult(intent, RESULT_PICK_IMAGE_CROP); } public void recordVideo(View view) { Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); // Workaround for Nexus 7 Android 4.3 Intent Returning Null problem // create a file to save the video in specific folder (this works for // video only) // mFileURI = getOutputMediaFile(MEDIA_TYPE_VIDEO); // intent.putExtra(MediaStore.EXTRA_OUTPUT, mFileURI); // set the video image quality to high intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // start the Video Capture Intent startActivityForResult(intent, RESULT_VIDEO_CAP); } public void showGooglePlayServicesAvailabilityErrorDialog(final int connectionStatusCode) { runOnUiThread(new Runnable() { public void run() { Dialog dialog = GooglePlayServicesUtil.getErrorDialog(connectionStatusCode, MainActivity.this, REQUEST_GOOGLE_PLAY_SERVICES); dialog.show(); } }); } /** * Check that Google Play services APK is installed and up to date. */ private boolean checkGooglePlayServicesAvailable() { final int connectionStatusCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); if (GooglePlayServicesUtil.isUserRecoverableError(connectionStatusCode)) { showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode); return false; } return true; } private void haveGooglePlayServices() { // check if there is already an account selected if (credential.getSelectedAccountName() == null) { // ask user to choose account chooseAccount(); } } private void chooseAccount() { startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER); } /** * Private class representing a missing configuration and what the developer * can do to fix the issue. */ private class MissingConfig { public final String title; public final String body; public MissingConfig(String title, String body) { this.title = title; this.body = body; } } // public Uri getOutputMediaFile(int type) // { // // To be safe, you should check that the SDCard is mounted // if(Environment.getExternalStorageState() != null) { // // this works for Android 2.2 and above // File mediaStorageDir = new // File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), // "SMW_VIDEO"); // // // This location works best if you want the created images to be shared // // between applications and persist after your app has been uninstalled. // // // Create the storage directory if it does not exist // if (! mediaStorageDir.exists()) { // if (! mediaStorageDir.mkdirs()) { // Log.d(TAG, "failed to create directory"); // return null; // } // } // // // Create a media file name // String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", // Locale.getDefault()).format(new Date()); // File mediaFile; // if(type == MEDIA_TYPE_VIDEO) { // mediaFile = new File(mediaStorageDir.getPath() + File.separator + // "VID_"+ timeStamp + ".mp4"); // } else { // return null; // } // // return Uri.fromFile(mediaFile); // } // // return null; // } private class UploadBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(REQUEST_AUTHORIZATION_INTENT)) { Log.d(TAG, "Request auth received - executing the intent"); Intent toRun = intent.getParcelableExtra(REQUEST_AUTHORIZATION_INTENT_PARAM); startActivityForResult(toRun, REQUEST_AUTHORIZATION); } } } }