I am trying to play DASH video stream, I am using Pallycon service to manage keys. The below code works fine when drmSessionManager set to the ExoPlayerFactory.newSimpleInstance (deprecated) instance, but When I set drmSessionManager seperately for media source, player shows blank screen. And not showing any error in logcat.
public class MainActivity extends AppCompatActivity {
private PallyconEventListener pallyconEventListener = new PallyconEventListener() {
#Override
public void onDrmKeysLoaded(Map<String, String> map) {
}
#Override
public void onDrmSessionManagerError(Exception e) {
}
#Override
public void onDrmKeysRestored() {
}
#Override
public void onDrmKeysRemoved() {
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PlayerView playerView = findViewById(R.id.player_view);
String siteId = "XXXX";
String siteKey = "XXXX";
PallyconWVMSDK WVMAgent = null;
try {
WVMAgent = PallyconWVMSDKFactory.getInstance(this);
WVMAgent.init(this, null, siteId, siteKey);
WVMAgent.setPallyconEventListener(pallyconEventListener);
} catch (PallyconDrmException e) {
e.printStackTrace();
} catch (UnAuthorizedDeviceException e) {
e.printStackTrace();
}
// TODO : 2.set content information
UUID drmSchemeUuid = UUID.fromString((C.WIDEVINE_UUID).toString());
Uri uri = Uri.parse("http://www.example.com/index.mpd");
String drmLicenseUrl = "http://license.pallycon.com/ri/licenseManager.do";
String cid = "COOL";
String userId = "lpa";
String ptoken = "";
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager = null;
try {
drmSessionManager = Objects.requireNonNull(WVMAgent).createDrmSessionManagerByToken(drmSchemeUuid, drmLicenseUrl, uri, userId, cid, ptoken, false);
} catch (PallyconDrmException e) {
e.printStackTrace();
}
DataSource.Factory dataSourceFactory = new DefaultHttpDataSourceFactory("cool");
SimpleExoPlayer exoPlayer = new SimpleExoPlayer.Builder(this, new DefaultRenderersFactory(this)).setTrackSelector(new DefaultTrackSelector(this)).build();
playerView.setPlayer(exoPlayer);
MediaSource mediaSource2 = new DashMediaSource.Factory(dataSourceFactory).setDrmSessionManager(drmSessionManager).createMediaSource(uri);
exoPlayer.prepare(mediaSource2);
exoPlayer.setPlayWhenReady(true);
}
}
Related
I have three activities, I capture all data but one from DetailActivity upon button click and save in database using Room; My intention is to insert all these data into the database and start ReviewActivity so as to get the arraylist of reviews and also insert it in the database. Everything seems to work fine until when I want to view review offline because I believe it has been saved, reviews does not get loaded.
This is my DetailActivity,
TextView overview_tv; ImageView image_tv; TextView name_tv; TextView ratings; Context context; TextView release_date; ImageView backdrop_poster; private ExpandableHeightListView trailers; public static ArrayList<Youtube> youtube; public static ArrayList<Review> reviews; TrailerViewAdapter adapter; public static DataObject data; DataObject dataObject; ArrayList<Review> savedReview; private static final String IMAGE_URL = "http://image.tmdb.org/t/p/w185/"; private static final String THE_MOVIEDB_URL2 = "https://api.themoviedb.org/3/movie/"; private static final String MOVIE_QUERY2 = "api_key"; private static final String API_KEY2 = "6cc4f47bd4a64e0117e157b79072ae37"; private static String SEARCH_QUERY2 = "videos"; public static int movieId; Button viewReviews; Button favourite; String movieRating; private static final int YOUTUBE_SEARCH_LOADER = 23; private static final int REVIEW_SEARCH_LOADER = 24; File file; String name; String overview; String releaseDate; int switcher; public static ArrayList<Review> favouriteReviews; TextView trev; AppDatabase mDb; //Navigation arrow on the action bar #Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { NavUtils.navigateUpFromSameTask(this); } return super.onOptionsItemSelected(item); } #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail); mDb = AppDatabase.getInstance(getApplicationContext()); youtube = new ArrayList<Youtube>(); reviews = new ArrayList<Review>(); adapter = new TrailerViewAdapter(this, youtube); //Credit to Paolorotolo #github trailers = findViewById(R.id.expandable_list); trailers.setAdapter(adapter); trailers.setExpanded(true); //Navigation arrow on the acton bar; check also override onOptionsItemSelected ActionBar actionBar = this.getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); } context = getApplicationContext(); Intent intent = getIntent(); if (intent == null) { closeOnError(); } switcher = getIntent().getIntExtra("switch", 3); overview_tv = findViewById(R.id.overview); image_tv = findViewById(R.id.image); name_tv = findViewById(R.id.name); ratings = findViewById(R.id.ratings); release_date = findViewById(R.id.release_date); backdrop_poster = findViewById(R.id.backdrop_poster); trev = findViewById(R.id.review_show); viewReviews = findViewById(R.id.review_button); favourite = findViewById(R.id.favourite_button); addListenerOnRatingBar(ratings); if (switcher != 2) { favourite.setVisibility(View.INVISIBLE); dataObject = (DataObject) getIntent().getParcelableExtra("array"); final String favouriteName = dataObject.getName(); final String favouriteOverview = dataObject.getOverview(); final String favouriteReleaseDate = dataObject.getReleaseDate(); ArrayList<Youtube> savedTrailer = dataObject.getTrailers(); savedReview = dataObject.getMovieReviews(); movieRating = dataObject.getRating(); name_tv.setText(favouriteName); overview_tv.setText(favouriteOverview); ratings.setText("Rating: " + movieRating); release_date.setText("Release Date: " + favouriteReleaseDate);// Toast.makeText(this, "Testing Reviews " + savedReview.get(0).getAuthor(), Toast.LENGTH_SHORT).show(); String imagePath = name_tv.getText().toString() + "0i"; String backdropPath = name_tv.getText().toString() + "1b"; try { DataObjectAdapter.downloadImage(imagePath, image_tv, this); } catch (Exception e) { e.printStackTrace(); } try { DataObjectAdapter.downloadImage(backdropPath, backdrop_poster, context); } catch (Exception e) { e.printStackTrace(); } if (savedTrailer != null) { TrailerViewAdapter lv = new TrailerViewAdapter(DetailActivity.this, savedTrailer); trailers.setAdapter(lv); switcher = 3; } } else { name = getIntent().getStringExtra("Name"); overview = getIntent().getStringExtra("Overview"); final String image = getIntent().getStringExtra("Image"); movieId = getIntent().getIntExtra("movieId", 1); final String backdrop = getIntent().getStringExtra("backdrop"); releaseDate = getIntent().getStringExtra("releaseDate"); movieRating = getIntent().getStringExtra("rating"); Log.i("this", "switch " + switcher); name_tv.setText(name); overview_tv.setText(overview); ratings.setText("Rating: " + movieRating); release_date.setText("Release Date: " + releaseDate); //load backdrop poster Picasso.with(context) .load(IMAGE_URL + backdrop) .fit() .placeholder(R.drawable.placeholder_image) .error(R.drawable.placeholder_image) .into(backdrop_poster); Picasso.with(context) .load(IMAGE_URL + image) .fit() .placeholder(R.drawable.placeholder_image) .error(R.drawable.placeholder_image) .into(image_tv); getSupportLoaderManager().initLoader(YOUTUBE_SEARCH_LOADER, null, this); //getSupportLoaderManager().initLoader(REVIEW_SEARCH_LOADER, null, this); //loadTrailers(); //loadReviews(); //populateKeys(); } /** * Here manages the views(list) for reviews */ viewReviews.setOnClickListener(new View.OnClickListener() { #Override public void onClick(View v) { if (switcher == 3) { startActivity(new Intent(DetailActivity.this, ReviewActivity.class) .putExtra("switch", 3)); } else { Log.i("this", "I am from initial" + switcher); startActivity(new Intent(DetailActivity.this, ReviewActivity.class).putExtra("id", movieId)); } } } ); favourite.setOnClickListener(new View.OnClickListener() { #Override public void onClick(View v) { data = new DataObject(); data.setName(name); data.setOverview(overview); data.setRating(movieRating); data.setReleaseDate(releaseDate); data.setTrailers(youtube);// data.setMovieReviews(reviews); try { saveImage(name_tv.getText().toString() + "0i", image_tv); saveImage(name_tv.getText().toString() + "1b", backdrop_poster); } catch (IOException e) { e.printStackTrace(); } Toast.makeText(context, "The movie is saved as a favourite", Toast.LENGTH_LONG).show(); AppExecutors.getInstance().diskIO().execute(new Runnable() { #Override public void run() { mDb.dataDao().insertData(data); } }); startActivity(new Intent(DetailActivity.this, ReviewActivity.class).putExtra("id", movieId) .putExtra(ReviewActivity.EXTRA_DATA_ID, 20)); } } ); }
And my ReviewActivity
public class ReviewActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<ArrayList<Review>>{ public static ArrayList<Review> reviews; public static List<DataObject> favouriteReviews; public static RecyclerView reviewList; ArrayList<Review> r; private static final int REVIEW_SEARCH_LOADER = 24; private static final String MOVIE_QUERY3 = "api_key"; private static final String API_KEY3 = "6cc4f47bd4a64e0117e157b79072ae37"; private static String SEARCH_QUERY3 = "reviews"; private static final String THE_MOVIEDB_URL3 = "https://api.themoviedb.org/3/movie/"; private static int movId; public static final String EXTRA_DATA_ID = "extraDataId"; private static final int DEFAULT_TASK_ID = -1; private int mTaskId = DEFAULT_TASK_ID; DataObject data1; AppDatabase mDb; ReviewAdapter revAdapter; int loaderSwitch; #Override protected void onResume() { super.onResume(); } #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_review); mDb = AppDatabase.getInstance(getApplicationContext()); reviews = new ArrayList<Review>(); favouriteReviews = new ArrayList<DataObject>(); reviewList = findViewById(R.id.review_list); LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext()); reviewList.setLayoutManager(layoutManager); reviewList.setHasFixedSize(true); int switcher = getIntent().getIntExtra("switch", 1); Intent intent = getIntent(); if (intent == null) { finish(); } Log.i("this", "swithcer " + switcher); Log.i("this loader", "Loader " + loaderSwitch); if (switcher == 3){ DataObject dataObject = (DataObject) getIntent().getParcelableExtra("ArrayOfReviews"); if (dataObject != null){ ArrayList<Review> movieReviews = dataObject.getMovieReviews(); Toast.makeText(this, "There are reviews saved", Toast.LENGTH_LONG).show(); revAdapter = new ReviewAdapter(this, movieReviews ); reviewList.setAdapter(revAdapter); } } else { movId = getIntent().getIntExtra("id", 20); revAdapter = new ReviewAdapter(this, reviews); reviewList.setAdapter(revAdapter); loadReviews(); //populateReview(); } DividerItemDecoration decoration = new DividerItemDecoration(this, VERTICAL); reviewList.addItemDecoration(decoration); } #Override protected void onStart() { super.onStart(); //loadReviews(); } public static URL buildUrl3(String stringUrl) { Uri uri = Uri.parse(THE_MOVIEDB_URL3).buildUpon() .appendPath(stringUrl) .appendPath(SEARCH_QUERY3) .appendQueryParameter(MOVIE_QUERY3, API_KEY3) .build(); URL url = null; try { url = new URL(uri.toString()); } catch (MalformedURLException exception) { Log.e(TAG, "Error creating URL", exception); } return url; } public void loadReviews(){ // COMPLETED (19) Create a bundle called queryBundle Bundle queryBundle = new Bundle(); // COMPLETED (20) Use putString with SEARCH_QUERY_URL_EXTRA as the key and the String value of the URL as the value// queryBundle.putString(SEARCH_QUERY_URL_EXTRA, url.toString()); // COMPLETED (21) Call getSupportLoaderManager and store it in a LoaderManager variable LoaderManager loaderManager = getSupportLoaderManager(); // COMPLETED (22) Get our Loader by calling getLoader and passing the ID we specified Loader<ArrayList<Review>> movieReviews = loaderManager.getLoader(REVIEW_SEARCH_LOADER); // COMPLETED (23) If the Loader was null, initialize it. Else, restart it. if (movieReviews == null) { loaderManager.initLoader(REVIEW_SEARCH_LOADER, queryBundle, this); } else { loaderManager.restartLoader(REVIEW_SEARCH_LOADER, queryBundle, this); } } #Override public Loader<ArrayList<Review>> onCreateLoader(int id, Bundle args) { return new AsyncTaskLoader<ArrayList<Review>>(this) { #Override protected void onStartLoading() { super.onStartLoading(); forceLoad(); } #Override public ArrayList<Review> loadInBackground() { String g = String.valueOf(movId); // Create URL object URL url = buildUrl3(g); // Perform HTTP request on the URL and receive a JSON response back String jsonResponse = ""; try { jsonResponse = getResponseFromHttpUrl(url); } catch (Exception e) { e.printStackTrace(); } reviews = MovieJsonUtils.parseReview(jsonResponse); return reviews; } }; } #Override public void onLoadFinished(Loader<ArrayList<Review>> loader, ArrayList<Review> dat) { if (reviews != null) { Intent intent = getIntent(); if (intent != null && intent.hasExtra(EXTRA_DATA_ID)) { //mButton.setText(R.string.update_button); if (mTaskId == DEFAULT_TASK_ID) { mTaskId = intent.getIntExtra(EXTRA_DATA_ID, DEFAULT_TASK_ID); AppExecutors.getInstance().diskIO().execute(new Runnable() { #Override public void run() { data.setMovieReviews(reviews); mDb.dataDao().updateData(data); //mDb.dataDao().insertData(data); final List<DataObject> task = mDb.dataDao().loadById(mTaskId); runOnUiThread(new Runnable() { #Override public void run() { populateUI(task); } }); } }); } } else { ReviewAdapter lv = new ReviewAdapter(ReviewActivity.this, reviews); reviewList.setAdapter(lv); } } } #Override public void onLoaderReset(Loader<ArrayList<Review>> loader) { }
Data gets loaded from MainActivity, the saved data is passed on to other activities as a parcellable bundle via intent, the passed data is displayed in DetailActivity but not in ReviewActivity.
Alternatively, if I can load reviews alongside YouTube keys from DetailActivity, I believe I can handle the database issue from there, but two Loaders wouldn't just work together, the app crashes; I am aware two AsyncTasks concurrently run together solved this problem, but I prefer to use Loaders because of performance on configuration change
Good day everyone, I would like to ask, hat is the cause of that ANR?. In my project I have service which is binded in a activity. Now when I exit in that activity the app is hang for a moment. My thought is that the service is still running though I unbind it in onStop() of the activity.
Here is my service class
public class SpeechService extends Service {
public interface Listener {
/**
* Called when a new piece of text was recognized by the Speech API.
*
* #param text The text.
* #param isFinal {#code true} when the API finished processing audio.
*/
void onSpeechRecognized(String text, boolean isFinal);
}
private static final String TAG = "SpeechService";
private static final String PREFS = "SpeechService";
private static final String PREF_ACCESS_TOKEN_VALUE = "access_token_value";
private static final String PREF_ACCESS_TOKEN_EXPIRATION_TIME = "access_token_expiration_time";
/** We reuse an access token if its expiration time is longer than this. */
private static final int ACCESS_TOKEN_EXPIRATION_TOLERANCE = 30 * 60 * 1000; // thirty minutes
/** We refresh the current access token before it expires. */
private static final int ACCESS_TOKEN_FETCH_MARGIN = 60 * 1000; // one minute
public static final List<String> SCOPE =
Collections.singletonList("https://www.googleapis.com/auth/cloud-platform");
private static final String HOSTNAME = "speech.googleapis.com";
private static final int PORT = 443;
private final SpeechBinder mBinder = new SpeechBinder();
private final ArrayList<Listener> mListeners = new ArrayList<>();
private volatile AccessTokenTask mAccessTokenTask;
private SpeechGrpc.SpeechStub mApi;
private static Handler mHandler;
private final StreamObserver<StreamingRecognizeResponse> mResponseObserver
= new StreamObserver<StreamingRecognizeResponse>() {
#Override
public void onNext(StreamingRecognizeResponse response) {
String text = null;
boolean isFinal = false;
if (response.getResultsCount() > 0) {
final StreamingRecognitionResult result = response.getResults(0);
isFinal = result.getIsFinal();
if (result.getAlternativesCount() > 0) {
final SpeechRecognitionAlternative alternative = result.getAlternatives(0);
text = alternative.getTranscript();
}
}
if (text != null) {
for (Listener listener : mListeners) {
listener.onSpeechRecognized(text, isFinal);
}
}
}
#Override
public void onError(Throwable t) {
Log.e(TAG, "Error calling the API.", t);
}
#Override
public void onCompleted() {
Log.i(TAG, "API completed.");
}
};
private final StreamObserver<RecognizeResponse> mFileResponseObserver
= new StreamObserver<RecognizeResponse>() {
#Override
public void onNext(RecognizeResponse response) {
String text = null;
if (response.getResultsCount() > 0) {
final SpeechRecognitionResult result = response.getResults(0);
if (result.getAlternativesCount() > 0) {
final SpeechRecognitionAlternative alternative = result.getAlternatives(0);
text = alternative.getTranscript();
}
}
if (text != null) {
for (Listener listener : mListeners) {
listener.onSpeechRecognized(text, true);
}
}
}
#Override
public void onError(Throwable t) {
Log.e(TAG, "Error calling the API.", t);
}
#Override
public void onCompleted() {
Log.i(TAG, "API completed.");
}
};
private StreamObserver<StreamingRecognizeRequest> mRequestObserver;
public static SpeechService from(IBinder binder) {
return ((SpeechBinder) binder).getService();
}
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler();
fetchAccessToken();
}
#Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mFetchAccessTokenRunnable);
mHandler = null;
// Release the gRPC channel.
if (mApi != null) {
final ManagedChannel channel = (ManagedChannel) mApi.getChannel();
if (channel != null && !channel.isShutdown()) {
try {
channel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Log.e(TAG, "Error shutting down the gRPC channel.", e);
}
}
mApi = null;
}
}
private void fetchAccessToken() {
if (mAccessTokenTask != null) {
return;
}
mAccessTokenTask = new AccessTokenTask();
mAccessTokenTask.execute();
}
private String getDefaultLanguageCode() {
final Locale locale = Locale.getDefault();
final StringBuilder language = new StringBuilder(locale.getLanguage());
final String country = locale.getCountry();
if (!TextUtils.isEmpty(country)) {
language.append("-");
language.append(country);
}
return language.toString();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public void addListener(#NonNull Listener listener) {
mListeners.add(listener);
}
public void removeListener(#NonNull Listener listener) {
mListeners.remove(listener);
}
/**
* Starts recognizing speech audio.
*
* #param sampleRate The sample rate of the audio.
*/
public void startRecognizing(int sampleRate) {
if (mApi == null) {
Log.w(TAG, "API not ready. Ignoring the request.");
return;
}
// Configure the API
mRequestObserver = mApi.streamingRecognize(mResponseObserver);
mRequestObserver.onNext(StreamingRecognizeRequest.newBuilder()
.setStreamingConfig(StreamingRecognitionConfig.newBuilder()
.setConfig(RecognitionConfig.newBuilder()
.setLanguageCode(getDefaultLanguageCode())
.setEncoding(RecognitionConfig.AudioEncoding.LINEAR16)
.setSampleRateHertz(sampleRate)
.build())
.setInterimResults(true)
.setSingleUtterance(true)
.build())
.build());
}
/**
* Recognizes the speech audio. This method should be called every time a chunk of byte buffer
* is ready.
*
* #param data The audio data.
* #param size The number of elements that are actually relevant in the {#code data}.
*/
public void recognize(byte[] data, int size) {
if (mRequestObserver == null) {
return;
}
// Call the streaming recognition API
mRequestObserver.onNext(StreamingRecognizeRequest.newBuilder()
.setAudioContent(ByteString.copyFrom(data, 0, size))
.build());
}
/**
* Finishes recognizing speech audio.
*/
public void finishRecognizing() {
if (mRequestObserver == null) {
return;
}
mRequestObserver.onCompleted();
mRequestObserver = null;
}
/**
* Recognize all data from the specified {#link InputStream}.
*
* #param stream The audio data.
*/
public void recognizeInputStream(InputStream stream) {
try {
mApi.recognize(
RecognizeRequest.newBuilder()
.setConfig(RecognitionConfig.newBuilder()
.setEncoding(RecognitionConfig.AudioEncoding.LINEAR16)
.setLanguageCode("en-US")
.setSampleRateHertz(16000)
.build())
.setAudio(RecognitionAudio.newBuilder()
.setContent(ByteString.readFrom(stream))
.build())
.build(),
mFileResponseObserver);
} catch (IOException e) {
Log.e(TAG, "Error loading the input", e);
}
}
private class SpeechBinder extends Binder {
SpeechService getService() {
return SpeechService.this;
}
}
private final Runnable mFetchAccessTokenRunnable = new Runnable() {
#Override
public void run() {
fetchAccessToken();
}
};
private class AccessTokenTask extends AsyncTask<Void, Void, AccessToken> {
#Override
protected AccessToken doInBackground(Void... voids) {
final SharedPreferences prefs =
getSharedPreferences(PREFS, Context.MODE_PRIVATE);
String tokenValue = prefs.getString(PREF_ACCESS_TOKEN_VALUE, null);
long expirationTime = prefs.getLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME, -1);
// Check if the current token is still valid for a while
if (tokenValue != null && expirationTime > 0) {
if (expirationTime
> System.currentTimeMillis() + ACCESS_TOKEN_EXPIRATION_TOLERANCE) {
return new AccessToken(tokenValue, new Date(expirationTime));
}
}
// ***** WARNING *****
// In this sample, we load the credential from a JSON file stored in a raw resource
// folder of this client app. You should never do this in your app. Instead, store
// the file in your server and obtain an access token from there.
// *******************
final InputStream stream = getResources().openRawResource(R.raw.credential);
try {
final GoogleCredentials credentials = GoogleCredentials.fromStream(stream)
.createScoped(SCOPE);
final AccessToken token = credentials.refreshAccessToken();
prefs.edit()
.putString(PREF_ACCESS_TOKEN_VALUE, token.getTokenValue())
.putLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME,
token.getExpirationTime().getTime())
.apply();
return token;
} catch (IOException e) {
Log.e(TAG, "Failed to obtain access token.", e);
}
return null;
}
#Override
protected void onPostExecute(AccessToken accessToken) {
mAccessTokenTask = null;
final ManagedChannel channel = new OkHttpChannelProvider()
.builderForAddress(HOSTNAME, PORT)
.nameResolverFactory(new DnsNameResolverProvider())
.intercept(new GoogleCredentialsInterceptor(new GoogleCredentials(accessToken)
.createScoped(SCOPE)))
.build();
mApi = SpeechGrpc.newStub(channel);
// Schedule access token refresh before it expires
if (mHandler != null) {
mHandler.postDelayed(mFetchAccessTokenRunnable,
Math.max(accessToken.getExpirationTime().getTime()
- System.currentTimeMillis()
- ACCESS_TOKEN_FETCH_MARGIN, ACCESS_TOKEN_EXPIRATION_TOLERANCE));
}
}
}
/**
* Authenticates the gRPC channel using the specified {#link GoogleCredentials}.
*/
private static class GoogleCredentialsInterceptor implements ClientInterceptor {
private final Credentials mCredentials;
private Metadata mCached;
private Map<String, List<String>> mLastMetadata;
GoogleCredentialsInterceptor(Credentials credentials) {
mCredentials = credentials;
}
#Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
final MethodDescriptor<ReqT, RespT> method, CallOptions callOptions,
final Channel next) {
return new ClientInterceptors.CheckedForwardingClientCall<ReqT, RespT>(
next.newCall(method, callOptions)) {
#Override
protected void checkedStart(Listener<RespT> responseListener, Metadata headers)
throws StatusException {
Metadata cachedSaved;
URI uri = serviceUri(next, method);
synchronized (this) {
Map<String, List<String>> latestMetadata = getRequestMetadata(uri);
if (mLastMetadata == null || mLastMetadata != latestMetadata) {
mLastMetadata = latestMetadata;
mCached = toHeaders(mLastMetadata);
}
cachedSaved = mCached;
}
headers.merge(cachedSaved);
delegate().start(responseListener, headers);
}
};
}
/**
* Generate a JWT-specific service URI. The URI is simply an identifier with enough
* information for a service to know that the JWT was intended for it. The URI will
* commonly be verified with a simple string equality check.
*/
private URI serviceUri(Channel channel, MethodDescriptor<?, ?> method)
throws StatusException {
String authority = channel.authority();
if (authority == null) {
throw Status.UNAUTHENTICATED
.withDescription("Channel has no authority")
.asException();
}
// Always use HTTPS, by definition.
final String scheme = "https";
final int defaultPort = 443;
String path = "/" + MethodDescriptor.extractFullServiceName(method.getFullMethodName());
URI uri;
try {
uri = new URI(scheme, authority, path, null, null);
} catch (URISyntaxException e) {
throw Status.UNAUTHENTICATED
.withDescription("Unable to construct service URI for auth")
.withCause(e).asException();
}
// The default port must not be present. Alternative ports should be present.
if (uri.getPort() == defaultPort) {
uri = removePort(uri);
}
return uri;
}
private URI removePort(URI uri) throws StatusException {
try {
return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), -1 /* port */,
uri.getPath(), uri.getQuery(), uri.getFragment());
} catch (URISyntaxException e) {
throw Status.UNAUTHENTICATED
.withDescription("Unable to construct service URI after removing port")
.withCause(e).asException();
}
}
private Map<String, List<String>> getRequestMetadata(URI uri) throws StatusException {
try {
return mCredentials.getRequestMetadata(uri);
} catch (IOException e) {
throw Status.UNAUTHENTICATED.withCause(e).asException();
}
}
private static Metadata toHeaders(Map<String, List<String>> metadata) {
Metadata headers = new Metadata();
if (metadata != null) {
for (String key : metadata.keySet()) {
Metadata.Key<String> headerKey = Metadata.Key.of(
key, Metadata.ASCII_STRING_MARSHALLER);
for (String value : metadata.get(key)) {
headers.put(headerKey, value);
}
}
}
return headers;
}
}
}
and here is my activity class
public class MainActivity extends AppCompatActivity implements MessageDialogFragment.Listener {
private static final String FRAGMENT_MESSAGE_DIALOG = "message_dialog";
private static final String STATE_RESULTS = "results";
private static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
private SpeechService mSpeechService;
private VoiceRecorder mVoiceRecorder;
private final VoiceRecorder.Callback mVoiceCallback = new VoiceRecorder.Callback() {
#Override
public void onVoiceStart() {
showStatus(true);
if (mSpeechService != null) {
mSpeechService.startRecognizing(mVoiceRecorder.getSampleRate());
}
}
#Override
public void onVoice(byte[] data, int size) {
if (mSpeechService != null) {
mSpeechService.recognize(data, size);
}
}
#Override
public void onVoiceEnd() {
showStatus(false);
if (mSpeechService != null) {
mSpeechService.finishRecognizing();
}
}
};
// Resource caches
private int mColorHearing;
private int mColorNotHearing;
// View references
private TextView mStatus;
private TextView mText, mResult;
private Button editButton, clearButton;
private SharedPreferences settings;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
mSpeechService = SpeechService.from(binder);
mSpeechService.addListener(mSpeechServiceListener);
mStatus.setVisibility(View.VISIBLE);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mSpeechService = null;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
final Resources resources = getResources();
final Resources.Theme theme = getTheme();
mColorHearing = ResourcesCompat.getColor(resources, R.color.status_hearing, theme);
mColorNotHearing = ResourcesCompat.getColor(resources, R.color.status_not_hearing, theme);
mStatus = (TextView) findViewById(R.id.status);
mText = (TextView) findViewById(R.id.text);
mResult = (TextView) findViewById(R.id.resultText);
editButton = (Button)findViewById(R.id.button1);
clearButton = (Button)findViewById(R.id.button2);
settings = getSharedPreferences("MyPreference", Context.MODE_PRIVATE);
clearButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Sounds sounds = new Sounds(getApplicationContext());
if(settings.getBoolean("muteAble", false ) == true){
sounds.playSound();
}
mResult.setText("");
}
});
editButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Sounds sounds = new Sounds(getApplicationContext());
if(settings.getBoolean("muteAble", false ) == true){
sounds.playSound();
}
Intent editIntent = new Intent(MainActivity.this, EditorActivity.class);
String forEditText = mResult.getText().toString();
editIntent.putExtra("forEdit", forEditText);
startActivity(editIntent);
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == android.R.id.home){
this.finish();
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onStart() {
super.onStart();
// Prepare Cloud Speech API
bindService(new Intent(this, SpeechService.class), mServiceConnection, BIND_AUTO_CREATE);
// Start listening to voices
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
== PackageManager.PERMISSION_GRANTED) {
startVoiceRecorder();
} else if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.RECORD_AUDIO)) {
showPermissionMessageDialog();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO},
REQUEST_RECORD_AUDIO_PERMISSION);
}
}
#Override
protected void onStop() {
// Stop listening to voice
stopVoiceRecorder();
// Stop Cloud Speech API
mSpeechService.removeListener(mSpeechServiceListener);
unbindService(mServiceConnection);
mSpeechService = null;
super.onStop();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
if (requestCode == REQUEST_RECORD_AUDIO_PERMISSION) {
if (permissions.length == 1 && grantResults.length == 1
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startVoiceRecorder();
} else {
showPermissionMessageDialog();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void startVoiceRecorder() {
if (mVoiceRecorder != null) {
mVoiceRecorder.stop();
}
mVoiceRecorder = new VoiceRecorder(mVoiceCallback);
mVoiceRecorder.start();
}
private void stopVoiceRecorder() {
if (mVoiceRecorder != null) {
mVoiceRecorder.stop();
mVoiceRecorder = null;
}
}
private void showPermissionMessageDialog() {
MessageDialogFragment
.newInstance(getString(R.string.permission_message))
.show(getSupportFragmentManager(), FRAGMENT_MESSAGE_DIALOG);
}
private void showStatus(final boolean hearingVoice) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mStatus.setTextColor(hearingVoice ? mColorHearing : mColorNotHearing);
}
});
}
#Override
public void onMessageDialogDismissed() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO},
REQUEST_RECORD_AUDIO_PERMISSION);
}
private final SpeechService.Listener mSpeechServiceListener =
new SpeechService.Listener() {
#Override
public void onSpeechRecognized(final String text, final boolean isFinal) {
if (isFinal) {
mVoiceRecorder.dismiss();
}
if (mText != null && !TextUtils.isEmpty(text)) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (isFinal) {
mText.setText(null);
mResult.append(" "+text.toString());
} else {
mText.setText(text);
}
}
});
}
}
};
}
Thank in advance for your help
I want to save a string from a TextArea to the device and then reload it after reopening the app. I have tried following the examples (link) but cant get it to work. Main problem arises when i try to read the file and use a StringInputConverter.
private void saveAndLoad(TextArea textArea){
File textFile = new File(ROOT_DIR,"text_file");
String text2 = textArea.getText();
String loadedFile = "none";
if (textFile.exists()){
FileClient fileClient = FileClient.create(textFile);
loadedFile = DataProvider.retrieveObject(fileClient.createObjectDataReader(
new StringInputConverter()));
}
try(FileWriter writer = new FileWriter(textFile)){
writer.write(textArea.getText());
} catch (IOException e) {
e.printStackTrace();
}
textArea.setText(text2);
}
Edit: inserted code which i tried to start reading file with and image of the error i am getting
If you check the DataProvider::retrieveObject documentation:
Retrieves an object using the specified ObjectDataReader. A GluonObservableObject is returned, that will contain the object when the read operation completed successfully.
It returns GluonObservableObject<String>, which is an observable wrapper of the string, not the string itself.
You need to get first the observable, and when the operation ends successfully you can retrieve the string:
if (textFile.exists()) {
FileClient fileClient = FileClient.create(textFile);
GluonObservableObject<String> retrieveObject = DataProvider
.retrieveObject(fileClient.createObjectDataReader(new StringInputConverter()));
retrieveObject.stateProperty().addListener((obs, ov, nv) -> {
if (ConnectState.SUCCEEDED.equals(nv)) {
loadedFile = retrieveObject.get();
}
});
}
This is a quick implementation of this functionality:
public class BasicView extends View {
private static final File ROOT_DIR;
static {
ROOT_DIR = Services.get(StorageService.class)
.flatMap(StorageService::getPrivateStorage)
.orElseThrow(() -> new RuntimeException("Error"));
}
private final File textFile;
private final TextField textField;
private String loadedFile = "none";
public BasicView(String name) {
super(name);
textFile = new File(ROOT_DIR, "text_file");
textField = new TextField();
VBox controls = new VBox(15.0, textField);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(30));
setCenter(controls);
}
#Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu")));
appBar.setTitleText("Basic View");
appBar.getActionItems().add(MaterialDesignIcon.SAVE.button(e -> save()));
appBar.getActionItems().add(MaterialDesignIcon.RESTORE_PAGE.button(e -> restore()));
}
private void save() {
try (FileWriter writer = new FileWriter(textFile)) {
writer.write(textField.getText());
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void restore() {
if (textFile.exists()) {
FileClient fileClient = FileClient.create(textFile);
GluonObservableObject<String> retrieveObject = DataProvider
.retrieveObject(fileClient.createObjectDataReader(new StringInputConverter()));
retrieveObject.stateProperty().addListener((obs, ov, nv) -> {
if (ConnectState.SUCCEEDED.equals(nv)) {
loadedFile = retrieveObject.get();
textField.setText(loadedFile);
}
});
}
}
}
So I'm working on a project which needs to cut up a video into multiple frames, and save them as Bitmaps on the device.
I'm using FFmpegMediaMetadataRetriever.getFrameAtTime() to obtain the individual frames, which is working, but is slow. To speed it up a bit I'm trying to implement multiple worker threads which go off and grab the frames, finally responding back to UI via an anonymous function.
I have a class MyVideoProcessor which handles the video processing, and this is called from my EditVideoActivity.
The threads start, and start processing, but shortly afterwards the EditVideoActivity dies (ANR).
From what I can see, there is nothing running on UI (apart from at the very end (which I confirm only runs once)) so not sure why the UI thread is being held up by the worker threads.
EDIT:
So I've switched out FFmpegMediaMetadataRetriever for the standard MediaMetadataRetriever and everything works. BUT I need to use FFmpegMediaMetadataRetriever, as the OPTION_CLOSEST in MMR doesn't work as it should.
EditVideoActivity:
if (mBackgroundThread==null || !mBackgroundThread.isAlive()) {
mBackgroundThread = new Thread(mMyVideoProcessor);
mBackgroundThread.start();
}
MyVideoProcessor:
public class MyVideoProcessor implements Runnable {
private static final String TAG = MyVideoProcessor.class.getSimpleName();
private MyVideo mMyVideo;
private final Context mContext;
public static final int FRAME_CUT_DURATION = 200;
private int mStartFrom = 0;
private int mCurrentDuration = 0;
private int mVideoDuration = 0;
private ArrayList<OnFrameUpdateListener> listeners = new ArrayList<>();
private ExecutorService mProcessors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public MyVideoProcessor(Context context, MyVideo myVideo) {
mContext = context;
mMyVideo = myVideo;
}
public void setOnFrameUpdateListener(OnFrameUpdateListener listener) {
listeners.add(listener);
}
public int getCurrentDuration() {
return mCurrentDuration;
}
public void setStartFrom(int startFrom) {
mStartFrom = startFrom;
}
#Override
public void run() {
if (!mMyVideo.getProcessed()) {
FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever();
retriever.setDataSource(mContext.getExternalFilesDir(null) + File.separator + mMyVideo.getVideo());
String time = retriever.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION);
retriever.release();
mVideoDuration = Integer.parseInt(time);
int i = 0;
if (mStartFrom > 0) {
Log.d(TAG,"Attempting restore");
i = mStartFrom+1;
}
for ( i=i;i<mVideoDuration;i+=FRAME_CUT_DURATION) {
mProcessors.execute(new ExtractImageExecutor(i));
}
}
}
public class ExtractImageExecutor implements Runnable {
private int mTime;
public ExtractImageExecutor(int time) {
mTime = time;
}
#Override
public void run() {
FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever();
retriever.setDataSource(mContext.getExternalFilesDir(null) + File.separator + mMyVideo.getVideo());
mCurrentDuration = mTime;
long startTime = System.currentTimeMillis();
Bitmap bitmap = retriever.getFrameAtTime(mTime*1000, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
long endTime = System.currentTimeMillis();
Log.d(TAG, "Took: " + ((endTime - startTime) / 1000f));
if (bitmap != null) {
try {
int thisFrame = 0;
if (mTime>0) {
thisFrame = mTime/FRAME_CUT_DURATION;
}
//noinspection StringBufferReplaceableByString
StringBuilder frameFilename = new StringBuilder();
frameFilename.append("VIDEO_");
frameFilename.append(thisFrame).append("_");
frameFilename.append(new SimpleDateFormat("yyyyMMddHHmm", Locale.UK).format(new Date()));
frameFilename.append(".jpg");
File frameFile = new File(mContext.getExternalFilesDir(null), frameFilename.toString());
FileOutputStream fos = new FileOutputStream(frameFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
mMyVideo.addFrame(thisFrame, frameFile);
/*for (OnFrameUpdateListener listener : listeners) {
listener.onFrameUpdate(mMyVideo);
}*/
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
retriever.release();
if ((mTime+FRAME_CUT_DURATION) > mVideoDuration) {
mMyVideo.setProcessed(true);
for (OnFrameUpdateListener listener : listeners) {
listener.onFrameUpdate(mMyVideo);
}
}
}
}
}
EditVideoActivity:
public class EditVideoActivity extends Activity {
private static final String TAG = EditVideoActivity.class.getSimpleName();
private ImageView mImageView;
private MyVideo mMyVideo;
private MyVideoProcessor mMyVideoProcessor;
private Thread mBackgroundThread;
private int mCurrentDuration = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_video);
String videoFilename = getIntent().getStringExtra("videoFilename");
if (videoFilename != null) {
mMyVideo = new MyVideo(MyVideo.TYPE_EXTERIOR,"TEST",new File(videoFilename));
mMyVideoProcessor = new MyVideoProcessor(this,mMyVideo);
} else {
Log.d(TAG, "There was a problem with the video file");
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
Log.d(TAG,"Saving Instance State");
outState.putParcelable("video", mMyVideo);
outState.putInt("currentDuration", mMyVideoProcessor.getCurrentDuration());
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
Log.d(TAG,"Restoring Instance State");
super.onRestoreInstanceState(savedInstanceState);
mMyVideo = (MyVideo) savedInstanceState.getParcelable("video");
mCurrentDuration = savedInstanceState.getInt("currentDuration");
}
#Override
protected void onResume() {
super.onResume();
mMyVideoProcessor = new MyVideoProcessor(this,mMyVideo);
final TextView totalFrames = (TextView) findViewById(R.id.totalFrames);
mImageView = (ImageView) findViewById(R.id.imageView2);
final SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar);
final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
progressBar.animate();
seekBar.setEnabled(false);
OnFrameUpdateListener onFrameUpdateListener = new OnFrameUpdateListener() {
#Override
public void onFrameUpdate(final MyVideo myVideo) {
if (myVideo.getProcessed()) {
File lastFrame = myVideo.getLastFrame();
totalFrames.setText(myVideo.getTotalFrames()+"");
mImageView.setImageBitmap(BitmapFactory.decodeFile(lastFrame.getAbsolutePath()));
seekBar.setEnabled(true);
progressBar.setVisibility(View.GONE);
}
}
};
mMyVideoProcessor.setOnFrameUpdateListener(onFrameUpdateListener);
if (mBackgroundThread==null || !mBackgroundThread.isAlive()) {
mBackgroundThread = new Thread(mMyVideoProcessor);
mBackgroundThread.start();
}
}
}
In my app,i want to show twitter login everytime a user tried to share a post.
I dont want to save the twitter credentials in shared preference,but when i tried to share a post in second time,it is not showing the login fields.
can anyone figure out the problem?
public class AuthorizationActivity extends Activity {
private TwitterActivity app;
private WebView webView;
static String token, verifier;
Webservice web;
OAuthCredentialsResponse credentials;
private WebViewClient webViewClient = new WebViewClient() {
#Override
public void onLoadResource(WebView view, String url) {
final OAuthHmacSigner signer = new OAuthHmacSigner();
Uri uri = Uri.parse(url);
if (url.startsWith(Constants.OAUTH_CALLBACK_URL)) {
try {
if (url.indexOf("oauth_token=")!=-1) {
token = uri.getQueryParameter("oauth_token");
verifier = uri.getQueryParameter("oauth_verifier");
signer.clientSharedSecret = Constants.CONSUMER_SECRET;
OAuthGetAccessToken accessToken = new OAuthGetAccessToken(
Constants.ACCESS_URL);
accessToken.transport = new ApacheHttpTransport();
accessToken.temporaryToken = token;
accessToken.signer = signer;
accessToken.consumerKey = Constants.CONSUMER_KEY;
accessToken.verifier = verifier;
credentials = accessToken.execute();
signer.tokenSharedSecret = credentials.tokenSecret;
+ credentials.tokenSecret);
;
if (null != token) {
webView.setVisibility(View.INVISIBLE);
finish();
} else if (url.indexOf("error=")!=-1) {
view.setVisibility(View.INVISIBLE);
}
}} catch (IOException e) {
e.printStackTrace();
}
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.authorization_view);
setUpViews();
String authURL = beginAuthorization();
webView.loadUrl(authURL);
}
private void setUpViews() {
webView = (WebView) findViewById(R.id.web_view);
webView.setWebViewClient(webViewClient);
}
public String beginAuthorization() {
try {
final OAuthHmacSigner signer = new OAuthHmacSigner();
OAuthAuthorizeTemporaryTokenUrl authorizeUrl;
signer.clientSharedSecret = Constants.CONSUMER_SECRET;
OAuthGetTemporaryToken temporaryToken = new OAuthGetTemporaryToken(Constants.REQUEST_URL);
temporaryToken.transport = new ApacheHttpTransport();
temporaryToken.signer = signer;
temporaryToken.consumerKey = Constants.CONSUMER_KEY;
temporaryToken.callback = Constants.OAUTH_CALLBACK_URL;
OAuthCredentialsResponse tempCredentials = temporaryToken.execute();
signer.tokenSharedSecret = tempCredentials.tokenSecret;
authorizeUrl = new OAuthAuthorizeTemporaryTokenUrl(Constants.AUTHORIZE_URL);
authorizeUrl.temporaryToken = tempCredentials.token;
String authorizationUrl = authorizeUrl.build();
System.out.println(authorizationUrl);
return authorizationUrl;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public void authorized() {
try {
AccessToken a = new AccessToken(credentials.token,credentials.tokenSecret);
Twitter twitter = new TwitterFactory().getInstance();
twitter.setOAuthConsumer(Constants.CONSUMER_KEY, Constants.CONSUMER_SECRET);
twitter.setOAuthAccessToken(a);
twitter.updateStatus("my first post");
Toast t = Toast.makeText(this,"Successfully Shared",Toast.LENGTH_LONG);
t.show();
} catch (TwitterException e) {
throw new RuntimeException("Unable to authorize user", e);
}
}
I think you missed one parameter in the URL
that's force_login = true , This will ask user to login even the session is not expired.
To read more go to this link RestAPI