2

I have implemented the onApplyWindowInsets callback in an Android Wear project. In the method, it calls isRound() to determine if the code is running on a round or rectangular Wear smartwatch. This callback is called from the round wear emulator. (Although isRound() returns false, which is wrong.) But the problem is that onApplyWindowInsets callback is never called from my Samsung Gear Live. Thus if one is inflating view from onApplyWindowInsets, the views do not get inflated. Has anyone gotten onApplyWindowInsets to fire on a real device? It seems it is not guaranteed. If so, then how can one inflate different views depending on the screen type?

WillT
  • 21
  • 1
  • 5

4 Answers4

2

In your layout you can set specific "sub" layouts for round/rectangular screens:

 <FrameLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent">

      <android.support.wearable.view.WatchViewStub
          xmlns:app="http://schemas.android.com/apk/res-auto"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:id="@+id/stub"
          app:rectLayout="@layout/rect_layout"
          app:roundLayout="@layout/round_layout"/>
 </FrameLayout>

If you use different ids for rect_layout and round_layout, you can check it on onCreate, like this:

@Override
public void onCreate(Bundle b) {
    super.onCreate(b);
    setContentView(R.layout.main_activity);
    WatchViewStub stub = (WatchViewStub) findViewById(R.id.stub);
    stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
        @Override
        public void onLayoutInflated(WatchViewStub stub) {
            mRectBackground = (RelativeLayout) findViewById(R.id.rect_layout);
            mRoundBackground = (RelativeLayout) findViewById(R.id.round_layout);
        }
    });
}

Either mRectBackground or mRoundBackground will be non null, not both. Docs here: https://developer.android.com/training/wearables/apps/layouts.html#UiLibrary

Other people try to use the strategy of using setOnApplyWindowInsetsListener, as shown here: https://github.com/xamarin/monodroid-samples/blob/master/wear/GridViewPager/GridViewPager/MainActivity.cs . It did not work for me.

Eider
  • 33
  • 5
  • Thanks! Your clever technique seems to have fixed this problem. (I say "seems", as I won't know for sure until the code is tested on a real round device that sets mRoundBackground to a non-null value.) – WillT Sep 01 '14 at 21:40
2

onApplyWindowInsets actually requires developer to call the WatchViewStub's onApplyWindowInsets method within the listener. For example:

WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {

    @Override
    public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
        //////////////////////////////////////////////////
        // IMPORTANT - the following line is required
        stub.onApplyWindowInsets(windowInsets);

        // Set the instance variable to say whether this is round...
        mIsRound = windowInsets.isRound();

        return windowInsets;
    }
});

Although it might not feel intuitive at first sight, this allow developer to override the default onApplyWindowInsets implementation if they choose.

Documentation for View.OnApplyWindowInsetsListener states that: "The listener may optionally call the parameter View's onApplyWindowInsets method to apply the View's normal behaviour as part of its own."

Hoi
  • 599
  • 2
  • 7
  • Unfortunately, I can't extend InsetActivity as my main class already extends FragmentActivity. I tried Hoi's method as an inner class, but also no luck. I've tried at least a dozen methods so far, but no luck detecting round or square screens on real devices. (The onLayoutInflated method always returns square, even on Moto 360 round screen. The onApplyWindowInsets callback never fires. ...etc) Anyone know of a method that actually works on real devices for detecting shape and inflating the correct layout, and not just in the emulator? I've been at this for weeks, and still no answer. – WillT Oct 25 '14 at 22:30
  • Tested on a real Moto 360 and this does not work :(. isRound() always return false no matter the device. – HyLian Nov 15 '14 at 12:01
  • The above answer edited on Dec 11 is now working. Comments from WillT on Oct 25 and HyLian on Nov 15 were valid for the previous answer (posted Oct 9) which uses InsetActivity (since been deprecated). Thanks for the feedback. – Hoi May 20 '15 at 22:57
0

Thank you Eider! Your clever technique seems to have fixed this problem. (I say "seems", as I won't know for sure until the code is tested on a real round device that sets mRoundBackground to a non-null value.)

Now that there are three Android Wear shapes (rect/square, round w/chin, and full round), I have added two global values to find the screen shape and then modified the callback as follows:

   stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
        @Override
        public void onLayoutInflated(WatchViewStub stub) {
            //mRectBackground = (RelativeLayout) findViewById(R.id.LinearLayout1);
            mRoundBackground = (RelativeLayout) findViewById(R.id.LinearLayout2);
            if (mRoundBackground != null) round = true;
            else round = false;

            WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
            Display display = window.getDefaultDisplay();
            //Added android.graphics.Point to imports for this next section
            Point point = new Point (0,0);
            display.getSize(point);
            scrnHeight = point.y;
            scrnWidth  = point.x;
            if (round && scrnWidth == scrnHeight) chin = false;
            else chin = true;
            //round = true; //For testing on the emulator!!!!!!
       }
    });

Does anyone know a better way to detect the chin on a Moto360?

UPDATE: Just ran this code on a Moto 360 and this technique did NOT detect a round screen. So for now I am just detecting if the height equals the width. But this is a bad technique for the future when more Android Wear devices are out. So the question still remains, how does one determine a round screen on the real Android Wear devices that are out there?

WillT
  • 21
  • 1
  • 5
  • hey. does the moto360 report its screen height as 320 then? – Sam Oct 20 '14 at 14:19
  • Do not use a test like "height equals the width", because this is the case for the G Watch (which has a square screen) at least. – Aladin Q Oct 21 '14 at 15:45
0

Unofficial way (without using WatchViewStub) - but for me it was way way easier. 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.

Michał Tajchert
  • 10,333
  • 4
  • 30
  • 47
  • Since you are copy pasting your answer why not reference also the other answer : http://stackoverflow.com/questions/24907557/android-wear-type-detection-round-or-square – Jimmy Kane Apr 15 '16 at 10:58