Get list of available chromecasts on demand - android

Ok, so I am trying to figure at how to get an up-to-date list of available chromecast devices, I'm doing this so that my app can check when the chromecast is not in use and then open my receiver app.
I am having some unexpected behaviour from the code below:
public class MainActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
...
mMediaRouterCallback = new MyMediaRouterCallback();
mMediaRouter = MediaRouter.getInstance(context);
mMediaRouteSelector = new MediaRouteSelector.Builder()
.addControlCategory(CastMediaControlIntent.categoryForCast(context.getString(R.string.app_id)))
.build();
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
}
This adds a MediaRouter callback to the MediaRouter. I have chosen to use the active scan flag.
private class MyMediaRouterCallback extends MediaRouter.Callback {
...
#Override
public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
Log.d(TAG, "Description 1 " + info.getDescription());
mSelectedDevice = CastDevice.getFromBundle(info.getExtras());
Log.d(TAG, "Description 2 " + mSelectedDevice.toString());
if(info.getDescription().equals("Chromecast")) {
// code to launch chromecast receiver app here.
}
}
}
My implementation of the MediaRouter.Callback overrides onRouteAdded, it simply prints some information about the devices it has found Description 1 describes the receiver app the device is using, description 2 gives its name.
However when this code is run initially the same device is discovered twice printing:
07-05 21:01:12.270: D/MainActivity(9730): Description 1 Casting HelloText
07-05 21:01:12.280: D/MainActivity(9730): Description 2 "Downstairs"
07-05 21:01:12.280: D/MainActivity(9730): Description 1 Casting HelloText
07-05 21:01:12.280: D/MainActivity(9730): Description 2 "Downstairs"
Then periodically the onRouteAdded callback is called sometimes only listing the device once, other times listing the device twice. My understanding however is that this callback should only be called when a new route is added.
I want to find all the available devices on command, not at random intervals that I can't control, what do I need to be doing? I can't find a callback that seems to be appropriate for this situation (such as whenever devices update/change), nor can I find a way to list them without using callbacks, so I'm a bit stuck.
(I have been basing these tests of the HelloText-Android example found here https://github.com/googlecast/CastHelloText-android, also I started this (my first android project) only a couple of days ago, so I apologise if I am missing something horrendously obvious)
Thanks in advance.

Call getRoutes() to get the list of known routes at the point in time that you desire. Iterate over them. Call matchesSelector() on each to filter out those that match your desired control category.

If you are listening for "onRouteAdded()", you would also need to listen to "onRouteRemoved()" to do a correct bookkeeping; if a device is added, it can be removed and added again so if you just listen to onRouteAdded(), it may seem it is being added multiple times. Getting the list from MedaiaRoute.getRoutes() might be easier if you don't want to be notified immediately and only want to know the list at certain points on demand.

Related

How to properly track playback position? [Android Media Broadcast Notifications Spotify API]

After reading the documentation on Spotify's Android Media Notifications API, https://beta.developer.spotify.com/documentation/android-sdk/guides/android-media-notifications/, I successfully managed to receive the notifications metadata and it is displayed properly on my app.
However, the notifications metadata is only updated when the queue changes, when the track changes, and when playback is changed, so unless one of these three actions happens, the "positionInMs" intent extra isn't sent.
As of right now as a workaround I am simply starting a timer using the time the intent was sent, the last known playback position, and the track duration to track current playback position.
This seemed to work at first, but after further testing I've realized that the timer I set can go out of sync, if the track the user is listening to freezes because of a slow internet connection.
Any ideas to properly track the playback position, while accounting for a slow internet connection? Or are there any alternatives I should look into?
I understand that this question is rather old, but I am going to answer anyway if anyone else comes across it.
I recommend constantly querying Spotify to get the playback position. One way you can do this is by using a timer and querying Spotify every given time frame. The below example queries Spotify every 100ms. If you want to reduce/increase the numbers of queries, you can simply use stopwatch.setClockDelay() and provide your required time
For instance, you can use this timer library
implementation 'com.yashovardhan99.timeit:timeit:1.2.0'
Then use the following code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spotify);
Stopwatch stopwatch = new Stopwatch();
stopwatch.setOnTickListener(this);
stopwatch.start();
}
#Override
public void onTick(Stopwatch stopwatch) {
Data.getAndroidSpotifyAppRemote().getPlayerApi().getPlayerState().setResultCallback(new CallResult.ResultCallback<PlayerState>() {
#Override
public void onResult(PlayerState playerState) {
Log.d("TAG", playerState.playbackPosition);
}
});
}
Don't forget to add the following code at the top of your class:
implements Stopwatch.OnTickListener

Android activity recognition issue

I am developing android native applications. My requirement is to get the current activity of the device like running,in_vehicle,still and so on. I used ActivityRecognitionAPI and set the pendingintent to receive the activity changes through IntentService. I gave 5 seconds interval for each updated. Its failed to provide the activity changes in certain period of time and again started providing activity. After that i preferred Awareness SnapshotAPI to get the activity state. Its also same result, failed to provide the activity regularly. Both APIs sometimes providing and many times not. I used GooglePlayServices 10.2.0 version for my developemnt. Anyone tell what is the reason for these things and solution to get regular activity updates..
Thanks in advance.
I am trying to show my app user's activity like he is walking, running and so on. This is my requirement.
Way 1:
//Google API client using ActivityRecognition.API
Intent intent = new Intent(mContext, RequestActivityService.class);
PendingIntent callbackIntent = PendingIntent.getService(mContext, 111,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(googleApiClient,5000, callbackIntent);
public class RequestActivityService extends IntentService {
public RequestActivityService() {
super("RequestActivityService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (ActivityRecognitionResult.hasResult(intent)) {
ActivityRecognitionResult result = ActivityRecognitionResult
.extractResult(intent);
DetectedActivity mostProbableActivity = result
.getMostProbableActivity();
int confidence = mostProbableActivity.getConfidence();
int activityType = mostProbableActivity.getType();
String activityName = getNameFromType(activityType);
}
}
** I tried this way to get activity updates. It started providing the activity info, but Intent service not called sometimes and again started firing the intent. So I am not able to show the correct activity information.
Way 2:
//Google API client using Awareness.API
Awareness.SnapshotApi.getDetectedActivity(googleApiClient).
setResultCallback(new ResultCallback<DetectedActivityResult>() {
#Override
public void onResult(#NonNull DetectedActivityResult detectedActivityResult) {
if (!detectedActivityResult.getStatus().isSuccess()) {
Log.i("Could not get the activity","");
return;
}
ActivityRecognitionResult ar = detectedActivityResult.getActivityRecognitionResult();
DetectedActivity probableActivity = ar.getMostProbableActivity();
String activityType = RequestActivityService.getNameFromType(probableActivity.getType());
int activityConfidence = probableActivity.getConfidence();
}
});
** I tried this another way, using this Api we can call this method recursively and get the activity information frequently. But Its also sometime providing and sometimes detectedActivityResult.getStatus() not success. If I am trying to get the status code and status message, status code returns 15 and status message will be null.
Both these ways are failed to give regular updates of activity and more over I used GooglePlayService 10.2.0 version. I have tested the GoogleSamples of ActivityRecognition from Github. That is also same result. I don't know what do to achieve my requirement. Hope now u can understand my requirement and things which I faced.
ActivityRecognitionAPI from Google doesn't give updates regularly. From what I have noticed, if there is a change in the confidence level of the activity or the activity changes altogether, then it'll send an update. Even then, it'll take time to ensure the data read isn't just noise of some kind.
I'm not sure why you need regular updates, but I would suggest changing the logic to accept the last given activity as the current activity, and only act upon the changes (i.e., STILL -> IN_VEHICLE).
Call this method again after getting response:
I would suggest to set detectionIntervalMillis to 0. That will lead to get data ASAP.( be aware of battery consumption )
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(googleApiClient,o, callbackIntent);
if there are no changes for long time, it will not send updates till change occur...

Android Cast - Media Router callback not returning

I'm trying to auto discover Cast devices. This is basically verbatim what I've seen for how to do this, however I never get the callback for either onRouteAdded or onRouteSelected.
I've tried changing which flags are used, but didn't get different results. Sometimes the route will be added, but never selected.
private void startSearchForDevicesAndCast() {
MediaRouter router = MediaRouter.getInstance(this);
int count = router.getRoutes().size();
List<MediaRouter.RouteInfo> j = router.getRoutes();
MediaRouteSelector selector = new MediaRouteSelector.Builder().addControlCategory(
CastMediaControlIntent.categoryForCast(getString(R.string.app_id))).build();
router.addCallback(selector, new MediaRouter.Callback() {
#Override
public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) {
super.onRouteAdded(router, route);
Log.i(TAG, "onRouteAdded: ");
router.selectRoute(route);
}
#Override
public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo route) {
super.onRouteChanged(router, route);
Log.i(TAG, "onRouteChanged: ");
}
#Override
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo route) {
Log.i(TAG, "onRouteSelected: ");
super.onRouteSelected(router, route);
}
}, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
}
I believe in your case, you would need to do a little bit more. Depending on the setup and structure of your app and some other factors, the route you are expecting may have already been discovered by the MediaRouter. In that case, you will not get an onRouteAdded() since it is already there. To accommodate this, one approach is after calling router.addCallback(..) (as you are already doing), get the list of all present routes by calling mMediaRouter.getRoutes() and then filter the list for the app id that you are interested in (by using the same selector that you have defined and using route.matchesSelector(selector)) and consider that as your initial set of discovered devices. From that point on, the onRouteAdded() and onRouteRemoved() can be used to update the list. As for onRouteChanged(), that sometimes has valuable information; for example when a cast device is rebooted, and when it comes up, at the very beginning it may not have the right configuration but soon after it gets its configuration and updates certain fields and then onRouteChanged() is called but in most cases, you may ignore that and just focus on the initial set and the ones that get added or removed. If you want to see how this can be put together, note that what I outlined above is very close to what the MediaRouterChooserDialog does internally and since the source to that is openly available in Media Router v7 support library, you can take a look and see how it can be done.

How many mayLaunchUrl we can run at a time?

I am trying to utilize ChromeCustomTabs into our project. I ran into several issue when I used mayLaunchUrl. I checked the code Google has on the github. I simply set up an button to test the mayLaunchURL (prerender feature), when I looked up the traffic using chrome dev tool. I did the the traffic and tab got trigger and the url got loaded ( it is simply a GET call with params). However, when I click it multiple times, (after 8-10times, with different params everytime), it STOP working. I stop seeing the requests sent out. (Not seen on chrome dev tool, nor the Proxy I set up).
I wonder if there is a limit times ( restriction) for mayLaunchURL feature, in other words, how many pages we can pre-render in this case? Is there a way to manually cancel the pre-render page and free the resource?
is there a restriction in terms of times to bindCustomTabsService? The way I did to call mayLaunchURL is to have an activity and kill the activity once I finish the tab. Can I bind the service each time even I “kill (finish)” the activtiy every time?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
customTabActivityHelper = new CustomTabActivityHelper();
customTabActivityHelper.setConnectionCallback(this);
}
#Override
protected void onStart() {
super.onStart();
customTabActivityHelper.bindCustomTabsService(this);
}
#Override
public void onCustomTabsConnected() {
Boolean mayLaunchUrlAccepted = customTabActivityHelper.mayLaunchUrl(Uri.parse(“the URL?f=“+params), null, null);
// the mayLaunchUrlAccepted always return true in my case. Even when there is no request sent.
}
Yes, mayLaunchURL() are very expensive in terms of battery/RAM/network, so it is throttled on app UID level. But limits get dropped after some time.
Best strategy is to use mayLaunchURL() if the confidence that the user will navigate to the URL is very high.
There is the "low confidence" mayLaunchURL() which is not throttled, but performs a more limited set of actions (currently preconnect, not specified which, may change). The low confidence mayLaunchURL is triggered by providing null as the uri and a list of URLs in otherLikelyBundles.

Measure Android app startup time

What is the most precise way to measure startup time of an Android app?
By startup time I mean the difference between 2. and 3. :
The app process is not running
User clicks on app icon in the launcher
Main Activity is fully initialized
So I basically need to somehow get time elapsed since JVM started and log it.
I understand I am too late to answer, nonetheless, this precisely answers the question.
This information gets logged on Logcat by default for API version 19 or higher.
From Android 4.4 (API level 19), logcat includes an output line containing a value called Displayed. This value represents the amount of time elapsed between launching the process and finishing drawing the corresponding activity on the screen.
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
The key is looking for it in the right place -
If you’re tracking logcat output from the command line, or in a terminal, finding the elapsed time is straightforward. To find elapsed time in Android Studio, you must disable filters in your logcat view. Disabling the filters is necessary because the system server, not the app itself, serves this log.
The extracts are from the documentation.
I'm going to interpret your question as 'Is my app startup time fast enough. How can I check I have done everything I can do?'
The startup time is largely a false metric as it will vary across devices and ROMs. I guess what you're most likely to be interested in is how much of your code is taking a long time to execute and what is potentially blocking the main thread.
I've found the most effective way of doing this is to use Traceview on the app start and then reviewing how long it takes the method to execute and if there are any gaps on the main thread.
Start tracing:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Debug.startMethodTracing("startup");
}
}
Stop tracing:
#Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Debug.stopMethodTracing();
}
Once the trace has been collected, you should be able to see anything that is having a major impact on startup time. In my case, seen below, there was a big gap on the UI thread where is was being blocked.
It transpired that both Crashlytics and Coremetrics were requiring a call to randomUUID() which was then being synchronized across threads and blocking the main thread. The solution was just to spin up a new thread to initialise the Coremetrics code.
This is something I would not have otherwise picked up with just measuring the startup time, but it actually sped up the app 'startup time' by a few hundred milliseconds.
Here's another snapshot after spinning off a separate thread for Coremetrics initialisation:
Check in adb shell in below manner.
adb shell
adb logcat -b events | grep am_activity_launch_time
[Output]
01-01 12:32:53.469 1236 1262 I am_activity_launch_time:
[0,205360373,com.sec.android.app.clockpackage/.ClockPackage,378,**378**,0]
Remarks:
Launch time for Clock is 378ms.
Wrap the entire onCreate() method in a TimingLogger. Just put this at the beginning:
TimingLogger timings = new TimingLogger(TAG, "methodA");
and this at the end:
timings.dumpToLog();
If you want to drop times at some intermediate step, you can do timings.addSplit("name"); to get the time it took to get to that step.
A simple way to display startup time in android.
Sometimes the Displayed line in the logcat output contains an additional field for total time. For example:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)
In this case, the first time measurement is only for the activity that was first drawn
Source: Time to initial display
It is possible to implement time tracking using the next code:
Override your Application:
public class CustomApplication extends Application {
public final static long APP_START_TIME = System.currentTimeMillis();
/**
* Do all other application stuff
*/
}
And add few rows to your main Activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final View contentView = findViewById(android.R.id.content);
contentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= 16) {
contentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
contentView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
long launchTime = System.currentTimeMillis() - CustomApplication.APP_START_TIME;
Log.e("TEST", "App launch time = " + launchTime);
}
});
}
}
And don't forget to define your custom application in Manifest:
<application
android:label="#string/app_name"
android:name=".CustomApplication" >
</application>
Important: You have to kill your application before launch, because Application stores static variable which tracks initial time.
Use SysTrace
Also the Trace class can be used to measure sections using
Trace.beginSection("name");
Trace.endSection();
This YouTube video is a quick primer as well.
I think this has been built into Firebase Console, under performance now
One possibility would be is to save the time at the beginning of the onCreate() method and at the end of the onCreate() method and then subtract those times from each other to get the time taken to initialize the app.

Categories

Resources