i wrote an application that run on round and square watches, with two layouts and a watchViewStub.
Since the moto 360 is sold over Europe i have many reports that Moto 360 doesn't load the rounded layout. With emulator, i can't reproduce this behavior even if i change locale as explain here : https://developer.android.com/guide/topics/resources/localization.html#testing
So i guess it's my code ...
Here's is how i've implemented it :
<android.support.wearable.view.WatchViewStub
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/watch_view_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:rectLayout="#layout/rect_activity_camera"
app:roundLayout="#layout/round_activity_camera">
Then in a fragment i inflate the WatchViewStub
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final WatchViewStub stub = (WatchViewStub) getView().findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override
public void onLayoutInflated(WatchViewStub stub) {
...
}
}
The fragment is used in a FragmentViewPager/FragmentGridPagerAdapter.
Until i get a Moto 360, any ideas on how i can debug this ?
Edit
WatchViewStub sample in Wear Sdk has two different behavior depends on language settings so i fill this issue : https://code.google.com/p/android/issues/detail?id=77642
Important
This issue is discussed on different posts. to avoid repeating the updated information only the issue on google code will be updated, and i'll complete this posts once the issue will be solved :
https://code.google.com/p/android/issues/detail?id=77642
There are many problems with inflating layouts that are caused by not correctly using WatchViewStub. I don't see enough code above to know exactly, but one common issue is when you register a listener for watch insets:
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
#Override
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
// Need to also call the original insets since we have overridden the original
// https://developer.android.com/reference/android/view/View.OnApplyWindowInsetsListener.html
stub.onApplyWindowInsets(windowInsets);
return windowInsets;
}
});
I see cases where people forget to return the windowInsets, or forget to call stub.onApplyWindowInsets(). This has the effect of giving a square layout instead of a round layout.
Other issues are caused by forgetting to put the same XML elements into the round.xml as the square.xml.
What is the error message you are getting in adb logcat?
I have some information for you about this bug.
The problem is triggered by the watch switching languages when pairing with a phone after a factory reset. You can avoid the issue by selecting the same language on the wearable as you are using on the phone, so that no change occurs afterwards when the devices are paired.
Instructions to fix the problem:
Factory reset the Moto 360.
When the wearable restarts, it will ask what language you would like to use. Select the same language that you are using on the phone (do not select the default of English)
On the phone, start the Android Wear companion app, and select from the overflow menu the option "Pair with a new wearable".
Pair the phone with the Moto 360.
Related
I'm using Xamarin Forms to produce a TabbedPage consisting of more ContentPages. This is the part of code causing trouble:
public void launchMainDesign(object s, EventArgs e) {
MainPage = new TabbedPage {
Children = {
new ContentPage {
Title = "Login",
Content = pages.loginContent,
BackgroundImage = "bgmain.jpg"
},
new ContentPage {
Title = "Sign Up",
Content = pages.signUpContent,
BackgroundImage = "bgmain.jpg"
}
}
};
}
It seems absolutely fine. I have both the images in my Drawable directory, with the build action set to "AndroidResource".
Whenever the launchMainDesign() function is fired by pressing a button, the app crashes immediately, both in emulator and a build version of the app on a tablet. Unfortunately, I can't test on iOS and WP.
I even tried putting the whole inside part of the function in a try/catch block and print out the exception, but the app just crashes nevertheless.
I am desperately trying to solve this simple problem for about a week now. No one seems to be having exactly the same issue as me. Weirdest thing is, I have a different app where I use exactly the same method and it works just fine. Can the Android Theme be causing this (I'm using Holo, in the working app, there's no theme specified)? That seems to be the only difference.
I also don't think this is caused by RAM struggles, as the image is only about 700 kilobytes (1080x1920) - for this example, I've only used one image.
It could be a memory issue, because even do the size is not big depending on the device resolution it might be trying to scale the image to the device dimensions.
Try checking this README:
https://github.com/xamarin/customer-success/blob/master/samples/Xamarin.Forms/SliderView/README.md
Explains Xamarin.Forms Android Image Memory Management so could help you get around the issue you might be having.
I'm adapting an existing phone application for tablets. The problem is that there are some small differences in the UI between the phone and the tablet.
For example, on the phone, there is a landing page and then a login page with a cancel button that goes back too the landing page.
On the tablet, the login fragment is on the landing page and the cancel button is removed. This means that I've made a check to see if the device is a tablet and if it is, I dunno find the view of the cancel button.
This seems hacky to me and i was wondering if there was a better way to do this. Thanks.
Tablet or phone ?
First of all you should know on which device you are. An elegant way (in my opinion) is to declare a resource in config.xml :
values/config.xml
<bool name="isTablet">false</bool>
values-sw600dp/config.xml
<bool name="isTablet">true</bool>
Then extends Application and keep the type of device running the app :
public static boolean IS_TABLET = false;
public void onCreate() {
super.onCreate();
MyApp.IS_TABLET = getResources().getBoolean(R.bool.isTablet);
}
Handling differents view
To handle differents view use the differents folders in /res
/layout for phone view
/layout-sw600dp for 7" tablet (you can just use this folder if there is no difference between 7 et 10")
/layout-sw720dp for 10" tablet
Handling code
Two solutions here :
1- The change between views are minor : keep the same activity/fragment and add some condition like
if(MyAPP.IS_TABLET) {
// DO something on tablet
} else {
// Do something on phone
}
2- If tablet and phone are very different create a new activity/fragment with a suffixe like :
HomeActvity => HomeActivityTablet
And add a condition on the loading of this particular view.
You can also works with differents namespace , depending on what give you best architecture.
Exemple
Have a look on the Google IO app's source code
I'm building an Android Wear app and trying to implement BoxInsetLayout for round screens. In my code, I want to detect if the device is round or not, so I'm using BoxInsetLayout's isRound() function, but it always returns false, even on the Moto 360.
Anyone know if there's a way to programmatically tell if the device is round?
The problem may be caused by calling isRound() at the wrong time. The round-ness is determined by the WindowInsets being delivered to the BoxInsetLayout. If you call isRound() very early before the insets have been delivered, you will get the wrong answer.
So if you have a "box" object which is the BoxInsetLayout, you would do this:
box.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
#Override
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
// Need to also call the original insets since we have overridden the original
// https://developer.android.com/reference/android/view/View.OnApplyWindowInsetsListener.html
box.onApplyWindowInsets(windowInsets);
// You can make calls to detect isRound() here!
// Return the insets so the BoxInsetLayout still works properly
return windowInsets;
}
});
Can you please send us the code related to the BoxInsetLayout that you are using?
According to Wayne answer on G+ it is a bug, for now we know what causes it, how to avoid it but only if user is aware of that, but fix for it is not released (yet).
https://plus.google.com/108847189842978537754/posts/5YiYb14i7ss
Quoting as post might be deleted/changed:
The problem is triggered by the watch switching languages when pairing with a phone after a factory reset. You can avoid the issue by
selecting the same language on the wearable as you are using on the
phone, so that no change occurs afterwards when the devices are
paired.
Instructions to fix the problem:
Factory reset the Moto 360.
When the wearable restarts, it will ask what language you would like to use. Select the same language that you are using on the phone
(do not select the default of English)
On the phone, start the Android Wear companion app, and select from the overflow menu the option "Pair with a new wearable".
Pair the phone with the Moto 360.
EDIT:
Using setOnApplyWindowInsetsListener (suggested by Wayne) I created small class that simplify using it a bit. https://github.com/tajchert/ShapeWear
Just copy ShapeWear.java class, and subscribe to screen shape detection event setOnShapeChangeListener() or call method ShapeWear.isRound() (can throw error is shape is not yet determined) or ShapeWear. getShape() - which can result in ShapeWear.SHAPE_UNSURE in same situation.
The FIT Radio App uses a MediaRoute.Callback that is initialized in my CommandInterface class, that controls playback for the normal audio as well as the Chromecast audio. The NowPlayingActivity is initially set as the mMediaRouteButtonHandler inside of the MediaRoute.Callback, only if the MediaRouteButton exists.
The now_playing.xml is now in the default layout, with protective measures in the java source code. Our first measure of protection against null pointer exceptions (with the G2) was removing the the MediaRouteButton from the default layout. The second measure that was taken to stop the null pointer exceptions was to add the null check in the NowPlayingActivity.setVisibility(int visibility) code sample below for any other version that may not provide the Button (N7, etc.).
The MediaRouter callback is added in the NowPlayingActvity.onResume(), and removed in the NowPlayingActvity.onPause(). The following sample displays the visibility handling in the MediaRoute.Callback.onRouteAdded:
public void onRouteAdded(MediaRouter router, RouteInfo route) {
if(hasMediaRouteButtonHandler()) mMediaRouteButtonHandler.setVisibility(View.VISIBLE);
++mRouteCount;
}
I have access to a Google G2, a Note 3, a Samsung S III, HTC One M7, and a Nexus 7. After starting the MediaRoute.Callback, the MediaRoute Button shows on all devices [using NowPlayingActivity.setVisibility(int visibility)], except with the Nexus 7 and the Google G2.
public void setVisibility(int visibility) {
if(getMediaRouteButton() != null) getMediaRouteButton().setVisibility(visibility);
}
I am using the findViewById(int) method in the NowPlayingActvity and it returns null in the latter cases (Nexus 7 & G2), but works on the S III, HTC One, and Note 3.
public MediaRouteButton getMediaRouteButton() {
return (MediaRouteButton) findViewById(R.id.media_route_button);
}
I have looked on StackOverflow for similar questions, and there were no real answers for the issue:
With the first question that I found the user figured it out eventually, and posted that he had no clear solution.
android.support.v7.app.MediaRouteButton does not display
Another question was answered by the poster, and the solution came from using a real device instead of the emulator:
Why my MediaRouteButton not available to find any cast devices?
I have debugged this with all the above devices, with Dirk (My Contractee) over my shoulder! So this is a critical issue guys, and we really need your help!
Thanks in advance,
Christopher Miller, posting on behalf of Dirk # Fit Radio.
I've written an android app with a view within an activity that relies on a callback to the view's wrapper's getHeight() function using an OnGlobalLayoutListener attached to the view's wrapper's viewTreeObserver to determine the amount of space it has to work with, during onCreate. Usually this is less than the 400px requested by chordDisplay in the xml below. This works perfectly in the android emulator, for a variety of screen sizes using android 2.1 and 4.03. However, on my kindle fire, the callback does not initially return the correct height when I launch the app in landscape (less than 400px are available) until I switch the orientation to portrait and back to landscape either manually or by code. This means the contents of my view aren't sized correctly initially.
sample logcat output when I initially launch the app in landscape:
04-22 17:31:28.249: D/onGlobalLayout(12979): chordDisplay.getHeight(): 400
then I switch to portrait and back to landscape:
04-22 17:32:44.546: D/onGlobalLayout(12979): chordDisplay.getHeight(): 350
I don't understand how this could be happening considering that all that happens during an orientation change is another call to onCreate() in the app, right? Which is the same thing that happens when I start the app.
Does anyone have any experience with similar orientation switching / layout bugs in their apps?/Have any ideas why this could be happening? Any help would be appreciated... Thanks.
code:
OnGlobalLayoutListener thelistener;
RelativeLayout chordDisplayWrapper;
TableRow.LayoutParams lp;
private ChordAdapter chordAdapter;
private HorizontalListView chordDisplay
thelistener = new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
chordDisplayWrapper.getViewTreeObserver().removeGlobalOnLayoutListener(this);
Log.d("onGlobalLayout", "chordDisplay.getHeight(): " + chordDisplay.getHeight());
lp = new TableRow.LayoutParams(chordDisplay.getHeight()/6 -2,chordDisplay.getHeight()/6 -2); //6 just works. I shrink it a tiny bit to compensate for some weird bug.
chordAdapter = (new ChordAdapter(mcontext, R.layout.row, magicbundle, lp));
chordDisplay.setAdapter(chordAdapter);
}
};
chordDisplayWrapper.getViewTreeObserver().addOnGlobalLayoutListener(thelistener);
xml layout for views involved:
<RelativeLayout
android:id="#+id/chordDisplayWrapper"
android:layout_width="wrap_content"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center" >
<berry.chordsfree.HorizontalListView
android:id="#+id/testerList"
android:layout_width="wrap_content"
android:layout_height="400px"
android:layout_centerInParent="true"
android:gravity="center" />
</RelativeLayout>
You may have solved this by now, but posting for posterity for those that may come across this after -
I'm having the same problem on my Nexus One, running a custom 2.3.7 ROM, but the code works on my Nexus Galaxy on stock 4.1.1.
Similar to you, I'm trying to resize certain views during onCreate using ViewTreeObserver. I've tried manually calling dispatchGlobalLayout and have ascertained it isn't an issue with onGlobalLayout not firing. And I played around with moving elements into the activity's onWindowFocusChanged without success (but I want to avoid having much resizing done there). This has cost me more than a day of work so I'm just using a quick/dirty fix for now. It appears normally if I just tweak the layout/view in question, after onCreate finishes:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!reset) {
LinearLayout frameItem = (LinearLayout) findViewById(R.id.frameItem);
frameItem.setVisibility(LinearLayout.GONE);
frameItem.setVisibility(LinearLayout.VISIBLE);
reset = true;
}
}