Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically determine screen shape in Android Wear

Tags:

wear-os

I'm looking for a technique to determine in Java if the Android Wear device screen is round or rectangular. Note that this isn't just about layouts; my code actually needs to know which shape it's working with, because they're handled differently.

As far as I can see from code samples online, two different approaches should be possible - but I've been unable to get either of them to work. I'll include them here to eliminate them from the running, or for possible troubleshooting (if anyone can see the problem with them). Please don't refer me to another SO post that just reiterates the solutions that aren't working for me here.

Note that all code here is running on the watch. Also, I'm still using Eclipse, FWIW.

The most straightforward method I've seen involves adding an onApplyWindowInsets() listener to a view in my layout. So I created a listener that looks like this:

@Override
public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
    if (insets.isRound()) {
     displayShape = "round";
    } else {
     displayShape = "rectangular";
    }
    return null;
}

and added it to the root view of my layout with code like this:

view.setOnApplyWindowInsetsListener(this);

in my onCreate() method. Looks OK as far as it goes - but the listener never gets called. I also found advice saying that I needed to invoke it manually, as such:

view.requestApplyInsets();

but that didn't seem to make any difference. I've experimented with putting it on different views, in different lifecycle methods, and so forth, but never once saw it actually get called in my app. This is running on my LG G Watch, BTW.

The second approach is something of a hack, and is based on the published WatchViewStub helper class. I jumped through the hoops to get the wearable support library imported into an Eclipse project, then added the following to my root layout:

<android.support.wearable.view.WatchViewStub 
    android:id="@+id/watch_view_stub"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:rectLayout="@layout/rect"
    app:roundLayout="@layout/round"
    />

and created rect.xml as such:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:id="@+id/layout_type"
    android:text="rectangular"
    />

and round.xml like this:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:id="@+id/layout_type"
    android:text="round"
    />

Finally, in my onCreate() I added the following Java code:

    final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
    stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
        @Override
        public void onLayoutInflated(WatchViewStub stub) {
            TextView layoutType = (TextView) findViewById(R.id.layout_type);
            displayShape = layoutType.getText().toString();
        }
    });

It's a long way around the block, but it should work, right? Not so much... displayShape is always set to "rectangular", indicating that it's always rect.xml that gets used, even when running on a round emulator. [I don't have round-screened hardware to try it on just yet.]

So does anyone see where I've gone wrong with either of these two approaches? Or can you suggest a third way which actually works?

like image 538
Sterling Avatar asked Sep 02 '14 22:09

Sterling


4 Answers

After several days spent chasing false leads, I've finally found the answer. It turns out that it's the android:theme of the application in the manifest that makes the difference.

In order for WatchViewStub to use the correct rect/round layouts, it appears that your application must use @android:style/Theme.DeviceDefault as its theme. Here's an example:

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.DeviceDefault">

I expect it would also work if you used a theme that inherited from DeviceDefault, though I haven't tested that. But it appears that if you use any other custom theme, WatchViewStub will not function correctly.

@WaynePiekarski, it'd be nice if this was documented somehere.

Also, here are a couple of other tips that I learned along the way:

  1. The rectangular layout always inflates before the round layout; IOW, on a round device, you'll get two onLayoutInflated() callbacks. This is kind of a pain if you're using the layout inflation to get the screen shape into your Java code, and that turns out to be necessary, because...

  2. Calling setOnApplyWindowInsetsListener() on WatchViewStub prevents the round layout from loading at all (at least in my testing). So if you try to use this callback to determine the screen shape, round devices will still get the square layout.

Finally, a bonus question: Is there any good reason why Android Wear doesn't just report its screen shape as a resource qualifier? You know, like -land, -large, and so on. Why on earth do we need to mess around with WatchViewStub at all?

like image 118
Sterling Avatar answered Jun 14 '23 15:06

Sterling


I'm not sure why it's necessary in your case to employ a callback, but an answer the general question of screen shape is here: Is there any way to detect if the clock is round?

That is, to acquire the current context, and test

context.getResources().getConfiguration().isScreenRound()
like image 39
Steve White Avatar answered Jun 14 '23 15:06

Steve White


In CanvasWatchFaceService.Engine their is a overide method available setOnApplyWindowInsets you can check whether insets is round or square

@Override
    public void onApplyWindowInsets(WindowInsets insets) {
        super.onApplyWindowInsets(insets);
        if(insets.isRound()){
          //round
        } 
        else{
          //square 
        }

    }
like image 24
rana_sadam Avatar answered Jun 14 '23 13:06

rana_sadam


https://plus.google.com/+NicolasPomepuy/posts/ZJ3KZK6uu2e#+NicolasPomepuy/posts/ZJ3KZK6uu2e

and from https://github.com/PomepuyN/WatchviewStubIssue/blob/bcad0de7fa473c757dc27f9dfe65e31561c6097f/wear/src/main/java/com/example/watchviewstubissue/ViewService.java

        mainView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { 
51             @Override 
52             public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { 
53                 if (insets.isRound()) { 
54                     Log.d("ViewService", "Round"); 
55                 } else { 
56                     Log.d("ViewService", "Square"); 
57                 } 
58                 return insets; 
59             } 
60         }); 

The diff between your code and his is that you are returning null and he is returning insets.

like image 45
bf2020 Avatar answered Jun 14 '23 15:06

bf2020