I've built a custom cast sender in my app that works perfectly - the only feature I need to add is a way to listen for the 'Play/Pause' and 'Skip' buttons, but Google's documentation (as far as I've been able to search for) doesn't give any clues, and after adding the functionality shown in Advanced Cast Features Docs did not work:
CastMediaOptions castMediaOptions = new CastMediaOptions.Builder()
.setMediaIntentReceiverClassName(CastIntentReceiver.class.getName())
.build();
return new CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.cast_id))
.setCastMediaOptions(castMediaOptions)
.build();
I have a CastIntentReceiver that extends MediaIntentReceiver that's referenced in CastOptionsProvider and in the manifest.
public class CastIntentReceiver extends MediaIntentReceiver {
public static String TAG = "CastIntentReceiver";
public CastIntentReceiver() {
Log.i(TAG, "CastIntentReceiver: Constructed!");
}
...
// The rest of the Override methods don't do anything
}
The receiver is working, because the Log print is working, but none of the Override methods are called (no Log printing).
Here are some additional details on my implementation:
All casting functions are in two separate classes, the CastManager (controller) and the CastControls fragment (view) which is added to the base of the MainActivity View (similar to YouTube). There are also Interfaces that trigger things between these two classes.
In the CastManager, I setup the UIMediaController and bind Views:
View view = CastingBridge.CAST_CONTROLS_VIEW.findViewById(R.id.cast_drawer_controls);
uiMediaController = new UIMediaController(activity);
SeekBar seekBar = (SeekBar) view.findViewById(R.id.cast_control_seek_bar);
TextView start = (TextView) view.findViewById(R.id.cast_control_time_start);
TextView end = (TextView) view.findViewById(R.id.cast_control_time_end);
ImageButton playPauseButton = (ImageButton) view.findViewById(R.id.cast_control_play_pause);
ImageButton rewindButton = (ImageButton) view.findViewById(R.id.cast_control_rewind);
ImageButton forwardButton = (ImageButton) view.findViewById(R.id.cast_control_forward);
ImageButton stopButton = (ImageButton) view.findViewById(R.id.cast_control_stop);
ProgressBar loadingSpinner = (ProgressBar) view.findViewById(R.id.cast_control_loading);
As stated before, all these work as they should, but I need to listen for (capture) the touch/click events so that when a video is paused or stopped, I can save the current watch length for resume purposes.
How do I implement MediaIntentReceiver to listen for these events? I've tried adding click listeners to the individual Views, but as expected, #Override onClick removes the initial intended functionality.
The documentation specifies what seem to be the methods I need, but how is this referenced?
I also tried adding the only listener available to UIMediaController:
uiMediaController.setPostRemoteMediaClientListener(new RemoteMediaClient.Listener() {
#Override
public void onStatusUpdated() {
Log.i(TAG, "onStatusUpdated: Status Updated");
}
});
This, however does not do anything, as the onStatusUpdated method supplies no arguments.
Can anyone help me shed some light onto this? I've been trying different things and searching for a couple days now, so time to ask for help.
Thanks!
The receiver you have defined (and MediaIntentReceiver in general) is used to handle actions from notification, lockscreen and cast dialog; so having a custom one affects the behavior when it is initiated from those places. If you are using UIMediaController, then you'd need to use onSendingRemoteMediaRequest() to be notified when user interacts with these controls.
Related
I need to add a new feature in my app and I have to put an image on the side of the layout. Such that the feature gets highlighted.
But, even if I write the code to make the view's visibility gone after one click. It still appears next time, when the app gets opened.
So, can anyone tell me how to do this correctly ??
Thanks in advance.
This code should solve your problem
public class MainActivity extends AppCompatActivity {
private ImageView imgTarget;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences sharedPreferences = getSharedPreferences("app_prefs",MODE_PRIVATE);
boolean imageVisible = sharedPreferences.getBoolean("img_visible",true);
Button button = findViewById(R.id.button);
imgTarget = findViewById(R.id.imgTarget);
if (!imageVisible){
imgTarget.setVisibility(View.GONE);
}
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(imageVisible){
imgTarget.setVisibility(View.GONE);
sharedPreferences.edit().putBoolean("img_visible",false).apply();
}
}
});
}
}
I hope it helps you.
Is your app connected to a database like sql, firebase or something else, if so you can create a counter variable in your database and control your view accordingly .
Based on your description, i'm guessing you've the gone after 1 click part done already.
Use SharedPreferences to see if the app has already been opened.
If yes, then set the Visibility to View.GONE in onCreate after you find the id. Otherwise, show it. Feel free to ask if there's anything else.
I have a pretty basic task: implementing HLS video streaming using Leanback framework and Exoplayer.
I use a simple single-fragment layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/video_fragment"
android:name="android.support.v17.leanback.app.VideoFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Apparently, VideoFragment comes with a default HUD which looks like this:
According to the docs, the recommended approach to bridging media player with playback controls is via PlaybackGlue. For example, Leanback showcase app uses MediaPlayer and thus uses a MediaPlayerGlue. I, for my purposes, have taken ExoPlayerGlue from this project.
private PlaybackFragmentGlueHost glueHost;
private PlaybackControlGlue glue;
#Override
public void onCreate(Bundle savedInstanceState) {
// ...
final VideoFragment videoFragment = (VideoFragment) getFragmentManager.findFragmentById(R.id.video_fragment);
glueHost = new VideoFragmentGlueHost(videoFragment);
glue = ExoPlayerGlue(this, player)
glue.setHost(glueHost);
}
This code does the job: it binds clicks to player events, so pause/resume and rewinding/fast-forwarding work as expected.
The tricky part is customizing playback controls. PlaybackGlueHost provides setPlaybackRow(Row row) and setPlaybackRowPresenter(PlaybackRowPresenter presenter) methods. Worth pointing out is that these methods have no effect in onCreate() so I either have to use handler or move them to onPostCreate():
#Override
public void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Buttons I need in my HUD
final Action skipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(this); // |<
final Action rewindAction = PlaybackControlsRow.RewindAction(this); // <<
final Action playPauseAction = PlaybackControlsRow.PlayPauseAction(this);
final Action fastForwardAction = PlaybackControlsRow.FastForwardAction(this); // >>
final Action skipNextAction = PlaybackControlsRow.SkipNextAction(this); // >|
final Action repeatAction = PlaybackControlsRow.RepeatAction(this);
final PresenterSelector controlPresenterSelector = ControlButtonPresenterSelector();
final PlaybackControlsRow playbackControlsRow = PlaybackControlsRow();
final ArrayObjectAdapter primaryAdapter = ArrayObjectAdapter(controlPresenterSelector);
final ArrayObjectAdapter secondaryAdapter = ArrayObjectAdapter(controlPresenterSelector);
// First row
primaryAdapter.add(skipPreviousAction);
primaryAdapter.add(rewindAction);
primaryAdapter.add(playPauseAction);
primaryAdapter.add(fastForwardAction);
primaryAdapter.add(skipNextAction);
// Second row
secondaryAdapter.add(repeatAction);
playbackControlsRow.primaryActionsAdapter = primaryAdapter;
playbackControlsRow.secondaryActionsAdapter = secondaryAdapter;
// Applying row to glue host
glueHost.setPlaybackRowPresenter(PlaybackControlsRowPresenter());
glueHost.setPlaybackRow(playbackControlsRow);
}
Now I have my customized playback row but the player no longer responds to button clicks.
I'm having a hard time trying to figure out how PlaybackGlue actually reacts to events from a PlaybackGlueHost. I know I can set OnActionClickedListener in a row presenter and handle actions manually but it kind of renders glue/host interaction model useless. How did it work in the first place? There is no default playback row I could find... I see that each Action corresponds to a set of key codes but I'm not sure what I can make of it.
Could anyone point me in the right direction? There's surprisingly little information on the subject.
Thanks.
Turned out PlaybackControlGlue had all the necessary methods (setControlsRow(), onCreatePrimaryActions(), onCreateSecondaryActions()) which I totally missed in the implementation I borrowed. The glue takes care of providing them to its host in onAttachedToHost() and then sets neccessary listeners.
I am using the VerticalGridFragment from the git sample to just display information and do not want user interaction. I successfully turned off the user focusing in the CardPresenter.cs but I would also like to change all the cards so they are not dim.
Here is a screenshot of the class and the dimming I would like to turn off. http://corochann.com/verticalgridfragment-android-tv-application-hands-on-tutorial-19-718.html
I have tried changing the alpha inside of the CardPresenter class but this does not seem to do anything. Any help would be appreciated!
CardPresenter.cs
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent) {
mDefaultBackgroundColor =
ContextCompat.getColor(parent.getContext(), R.color.default_background);
mSelectedBackgroundColor =
ContextCompat.getColor(parent.getContext(), R.color.selected_background);
mDefaultCardImage = parent.getResources().getDrawable(R.drawable.movie, null);
ImageCardView cardView = new ImageCardView(parent.getContext()) {
#Override
public void setSelected(boolean selected) {
updateCardBackgroundColor(this, selected);
super.setSelected(selected);
}
};
cardView.setAlpha(1.0f);
cardView.setFocusable(false);
cardView.setFocusableInTouchMode(false);
updateCardBackgroundColor(cardView, false);
return new ViewHolder(cardView);
}
create your presenter like so:
VerticalGridPresenter gridPresenter = new VerticalGridPresenter(FocusHighlight.ZOOM_FACTOR_LARGE,false);
the "false" is for enable / disable dimming
You may want to start using these helper classes that are primarily used for applying dim level or color to your View.
ColorOverlayDimmer
Helper class for assigning a dim color to Paint. It holds the alpha value for the current active level.
ColorFilterDimmer
Helper class for applying a dim level to a View. The ColorFilterDimmer uses a ColorFilter in a Paint object to dim the view according to the currently active level.
Sample implementation codes in Java can be found here. Hope it helps!
I have a layout which contains lots of images. What I have to do is when an image is clicked, I have to show its details. But I don't want to have onClickListeners for all the images. How can I achieve this?
You don't have to have different handlers for all the images. Instead use one handler for all the images. This would make your code cleaner, manageable and solve your problem too.
public void onCreate(Bundle bundle) {
//...
OnClickListener mHandler = new OnClickListener() {
#Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.img1:
//..
break;
case R.id.img2:
//....
break;
}
}
};
ImageButton btn1 = (ImageButton)findViewById(R.id.img1);
ImageButton btn2 = (ImageButton)findViewById(R.id.img2);
//...
btn1.SetOnClickListener(mHandler);
btn2.SetOnClickListener(mHandler);
//...
}
One Listener to rule them all.
Implement onClick() on an object, register it as listener
In onClick(), examine the View object passed as parameter to determine which of the images was clicked. You can do anything from getId() to casting it to (ImageView) and getting the actual image out.
Once you know which image was clicked, do what you will with it.
If you're looking to implement custom behavior for an ImageView (or whatever), and then have multiple instances of that type of view, you should subclass the ImageView and put your listener in there. Then you've got an encapsulated View that implements the custom behavior you want, and if you decide later that you want more or less or them, or to put them in another place, it's easy to move the View and its behavior without ripping apart your Activity.
basically I want to encapsulate a simple component from code that I already have.
Basically it's a LinearLayout with buttons inside. These buttons will make changes to a ListView, and there is also some other small stuff that it will do.
Currently I have a XML layout with those, and I programmatically setup everything else: the buttons, the interaction between the list and the other small stuff.
Obviously I thought to myself, let's encapsulate this.
I started out trying to extend the LinearLayout and adding the buttons.
Already I have no idea how to inflate the buttons to add to the view
What method do I override to create this buttons just before the view gets created without messing with the measures and inflations, etc.
I've looked around but the custom components I see are either completely new components or components that simply add small functionality to the custom ones.
Is there some guidelines for doing this?
Good tutorials/examples?
Any help is appreciated. Thanks !
EDIT:
Okay, here is a little more specific stuff.
Basically I want to create a View that holds filter buttons for a ListView. This will be used in different places with different filters, so I need flexibility for the buttons.
Basically I'd like to do something like this:
CustomView view = new CustomView(activity);
view.addButton("Lala", new OnFilterClickListener {
onClick(ListView list, View v) {
// Do the filtering
}
});
mListView.addHeaderView(view);
I want the view to adapt it's weights for showing the buttons, show the user which filter is active, stuff like that.
But I still don't really know how to make those dynamically added buttons appear, where do I generate them, how to inflate them and stuff like that.
public class myLayout extends LinearLayout {
//...
public void addButton(String text, OnClickListener listener) {
Button newButton = new Button(mContext);
newButton.setText(text);
newButton.setOnClickListener(listener);
//Say we want the weights to be equal
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.Fill_PARENT, 1);
addView(newButton, params);
}
//...
}
You can even do something to the view before dispatching the click like this:
public class myLayout extends LinearLayout {
//...
public void addButton(String text, final OnClickListener listener) {
Button newButton = new Button(mContext);
newButton.setText(text);
newButton.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
//do whatever you want
//like change background of button or something
//finally
listener.onClick(v);
}
});
//Say we want the weights to be equal
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.Fill_PARENT, 1);
addView(newButton, params);
}
//...
}