Java tutorial
//MIT License Copyright 2017 PSU ASL Capstone Team package com.psu.capstonew17.pdxaslapp; import android.Manifest; import android.app.ProgressDialog; import android.content.Intent; import android.content.pm.PackageManager; import android.media.MediaMetadataRetriever; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.Toast; import android.widget.VideoView; import com.psu.capstonew17.backend.api.Card; import com.psu.capstonew17.backend.api.CardManager; import com.psu.capstonew17.backend.api.Deck; import com.psu.capstonew17.backend.api.ObjectAlreadyExistsException; import com.psu.capstonew17.backend.api.Video; import com.psu.capstonew17.backend.api.VideoManager; import com.psu.capstonew17.backend.data.ExternalCardManager; import com.psu.capstonew17.backend.data.ExternalDeckManager; import com.psu.capstonew17.backend.data.ExternalVideoManager; import java.util.ArrayList; import java.util.List; public class CreateCardActivity extends BaseActivity implements View.OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback { //cases for the activity result struct private static final int GET_VIDEO = 1; //cases for the perm request result struct private static final int REQ_CAMERA_PERMS = 2; //min and max length of an answer for a card private static final int MIN_LABEL_LENGTH = 3; private static final int MAX_LABEL_LENGTH = 250; private static final int MIN_VIDEO_LENGTH = 2000; private static final int MAX_VIDEO_LENGTH = 30000; private static final String SELECT_VIDEO = "Select Video"; //activity elements private Button bttSubmit; private Uri videoUri; private EditText editText; private VideoView videoView; private ProgressDialog progressDialog; //a list for the listview and a list for all of the decks private List<ListRow> listRows; private List<Deck> deckList; //card attributes private String videoLabel; private Video video; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_create_card); Button bttGetVideo; Button bttRecordVideo; ListView listView; //submit button should be invisible until a video has been imported. bttSubmit = (Button) findViewById(R.id.button_submit); bttSubmit.setText(R.string.button_submit); bttSubmit.setVisibility(View.GONE); bttSubmit.setOnClickListener(this); bttGetVideo = (Button) findViewById(R.id.buttonFromGallery); bttGetVideo.setOnClickListener(this); bttRecordVideo = (Button) findViewById(R.id.buttonRecordVideo); bttRecordVideo.setOnClickListener(this); progressDialog = new ProgressDialog(this); progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); progressDialog.setMessage(getResources().getString(R.string.importing_video)); progressDialog.setIndeterminate(true); progressDialog.setCanceledOnTouchOutside(false); editText = (EditText) findViewById(R.id.edit_text_video_answer); editText.setOnClickListener(this); videoView = (VideoView) findViewById(R.id.videoView_create_card); videoView.setVisibility(View.GONE); //get the list of all decks in the db deckList = ExternalDeckManager.getInstance(this).getDecks(null); if (deckList.size() > 0) findViewById(R.id.noDecksText).setVisibility(View.GONE); listRows = new ArrayList<>(); //populate the list rows for the list view. for (int i = 0; i < deckList.size(); i++) listRows.add(new ListRow(deckList.get(i).getName(), false)); //create the list view. listView = (ListView) findViewById(R.id.list_items); listView.setAdapter(new CustomArrayListAdapter(this, R.layout.list_row, listRows)); } @Override public void onClick(View view) { switch (view.getId()) { //user wants to record a video for the new card case R.id.buttonRecordVideo: //check perms, if we don't have then then request them if (this.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) && PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)) { dispatchTakeVideoIntent(); } else { ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.CAMERA }, REQ_CAMERA_PERMS); } break; //user wants to use a video from the gallery. check for external storage perms. //if we don't have them, then request them. case R.id.buttonFromGallery: dispatchGalleryIntent(); break; //user is finished creating this card. case R.id.button_submit: videoLabel = editText.getText().toString().trim(); //make sure that the video imported successfully //and that the length of the answer is in valid range if (!videoLabelCheck() || video == null) { Toast.makeText(this, R.string.import_video_error, Toast.LENGTH_SHORT).show(); } else { CardManager cardManager = ExternalCardManager.getInstance(this); try { //video and label look good, create the card. Card card = cardManager.buildCard(video, videoLabel); //add the card to all of the selected decks. for (int i = 0; i < listRows.size(); i++) { ListRow curr = listRows.get(i); if (curr.isChecked) { Deck slctdDeck = deckList.get(i); List<Card> cards = slctdDeck.getCards(); cards.add(card); slctdDeck.commit(); } } finish(); //cards can't have the same video! } catch (ObjectAlreadyExistsException e) { Toast.makeText(this, R.string.card_already_exists, Toast.LENGTH_SHORT).show(); } } break; } } //gets the result of any perms we requested @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] perms, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, perms, grantResults); switch (requestCode) { //if we needed camera perms case REQ_CAMERA_PERMS: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { dispatchTakeVideoIntent(); } else { Toast.makeText(this, R.string.card_camera_perm_error, Toast.LENGTH_SHORT).show(); } break; } } //if the label the correct length? private boolean videoLabelCheck() { //trim it to remove leading or training white space when you get it videoLabel = editText.getText().toString().trim(); if (videoLabel.length() < MIN_LABEL_LENGTH || videoLabel.length() > MAX_LABEL_LENGTH) { //the user's answer is too short or long, let them now so they can fix it. StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(getResources().getString(R.string.card_name_lngth_error1)); stringBuilder.append(MIN_LABEL_LENGTH); stringBuilder.append(getResources().getString(R.string.card_name_lngth_error2)); stringBuilder.append(MAX_LABEL_LENGTH); Toast.makeText(this, stringBuilder.toString(), Toast.LENGTH_SHORT).show(); return false; } return true; } //call/display the gallery so that the user can select a video. private void dispatchGalleryIntent() { Intent intent = new Intent(); intent.setType("video/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(Intent.createChooser(intent, SELECT_VIDEO), GET_VIDEO); } //call/display the camera so that the user can record a video. //"Alright Mr. DeMille, I'm ready for my closeup!" private void dispatchTakeVideoIntent() { Intent takeVideoIntent = new Intent(); takeVideoIntent.setAction(MediaStore.ACTION_VIDEO_CAPTURE); if (takeVideoIntent.resolveActivity(getPackageManager()) != null) { startActivityForResult(takeVideoIntent, GET_VIDEO); } else { Toast.makeText(getApplicationContext(), R.string.card_record_video_error, Toast.LENGTH_SHORT).show(); } } //poorly named, this actually starts the video and makes hidden views visible protected void startVideo() { videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mp.setLooping(true); } }); video.configurePlayer(videoView); videoView.setVisibility(View.VISIBLE); bttSubmit.setVisibility(View.VISIBLE); videoView.start(); } //poorly named, this actually starts the video and hides views protected void stopVideo() { videoView.stopPlayback(); videoView.setVisibility(View.GONE); bttSubmit.setVisibility(View.GONE); } @Override protected void onResume() { super.onResume(); if (video != null) startVideo(); } //get the results from activities that... // ...return results... @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { switch (requestCode) { //We be getting a video! yay! case GET_VIDEO: if (resultCode == RESULT_OK) { videoUri = intent.getData(); if (videoUri != null) { //Verify length of video is greater than two seconds MediaMetadataRetriever retriever = new MediaMetadataRetriever(); retriever.setDataSource(this, videoUri); int endTime = Integer .parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)); if (endTime < MIN_VIDEO_LENGTH || endTime > MAX_VIDEO_LENGTH) { Toast.makeText(this, R.string.bad_video_length, Toast.LENGTH_SHORT).show(); } else { //if they had previously imported a video but changed their minds and imported //a different video then we need to stop payback of the old one and hide some //views while the new one imports. stopVideo(); //lets get the import options the user wants VideoManager.ImportOptions imo = new VideoManager.ImportOptions(); imo.startTime = 0; imo.endTime = endTime; imo.quality = 20; imo.cropRegion = null; //block with a spin wheel while the video is imported progressDialog.show(); //now we can import the new video. video = null; VideoManager vm = ExternalVideoManager.getInstance(this); vm.importVideo(this, videoUri, imo, new VideoManager.VideoImportListener() { //this is behaving weirdly with a horizontal progress bar, so for now I'm //ignoring it in favor of a spin wheel @Override public void onProgressUpdate(int current, int max) { } //this is called when the import has completed //we get the video, display it and the submit button, //and then hide the progress dialog. @Override public void onComplete(Video vid) { video = vid; startVideo(); progressDialog.dismiss(); Toast.makeText(CreateCardActivity.this, R.string.video_delete_safe, Toast.LENGTH_LONG).show(); } //if importing fails. @Override public void onFailed(Throwable err) { Toast.makeText(CreateCardActivity.this, R.string.import_video_error, Toast.LENGTH_SHORT).show(); progressDialog.dismiss(); } }); } } } break; } } }