Monday, August 8, 2011

Orientation for both phones and tablets

Tablets are now a new component to take into account when programming applications on Android.
And it brings issues with your application orientation...

My game Word Prospector was meant to be played in portrait mode on a phone.
But on tablets, I want it to be played in landscape ( as it feels more natural for tablets ).

But how to achieve that ?

Activity orientation is fixed in the manifest, and you can't have different manifests for different screen configurations.

So how to manage that ?
I found three different ways...

First solution : different apk for different screen configurations

Now that the Android market gives us support for multiple apk, ( see here ), you can use it just to have some differences in the manifest.
So you can have the very same application and only have different orientations in the manifest, and let the market make the work for you.

But having several apk is painful for developers : it's a lot of work to develop, and to maintain.
So I would  not recommend this solution.

Second Solution : have some activity code to manage the orientation

You can impose the orientation of your activity in the onCreate method of the activity, with the setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_XXX ) function.

So you can have some code like this :
if ( isXLargeScreen() )
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
else
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

With this code, when there is an orientation change, the activity is destroyed, then re created.
To avoid this destruction / recreation step, that would break the smoothness of the user experience, you have to disconnect the destruction of the activity mechanism.
So you have to add a
android:configChanges="keyboardHidden|orientation"
parameter in the activity declaration in the manifest, and add an empty onConfigurationChanged method.

Now you can even be more flexible.
If you want one configuration ( for instance the tablet one ) to handle both orientation, and the other ( the smartphone ) to handle only one orientation, you can do it :

In the OnCreate method, impose the orientation only for the smartphone :
if ( ! isXLargeScreen() )
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

Then in the onConfigurationChanged, you have to recreate the Activity only when on tablet. And in this case, you have to save the activty state, and restore it, as the classic destruction / creation of the activity is deactivated :

    public void onConfigurationChanged (Configuration newConfig)
    {
        //Log.d("tag", "config changed");
        super.onConfigurationChanged(newConfig);

        if ( ! isXLargeScreen() )
            return;
      
        // CODE FOR ROTATION
        // FOR BIGSCREENS :
        SaveActivityState();
        setContentView( R.layout.MyActivity );
        RestoreActivityState();
    }

Third solution : let's get back to the manifest...

The manifest really is the tool Android developers gave us to handle the orientation...
So my last ( and prefered ) solution is to have two different activities, with different orientation capacities :

        <activity     android:name="LetterGame"
                    android:screenOrientation="portrait"
                    android:configChanges="keyboardHidden|orientation"
                      android:label="@string/app_name">
        </activity>
        <activity     android:name="LetterGameLandscape"
                    android:configChanges="keyboardHidden|orientation"
                    android:screenOrientation="landscape"
                      android:label="@string/app_name">
        </activity>


and to create a MyActivityLandscape class, that just do ... nothing !
It just inherits from MyActivity :

package com.alocaly.LetterGame;

public class MyActivityLandscape extends MyActivity
{
}

Then you just have to choose what activity to launch in the caller activity :

Intent i;
if ( isXLargeScreen() )
    i = new Intent(MainMenu.this, MyActivityLandscape.class);
else
    i = new Intent(MainMenu.this, MyActivity.class);
startActivity( i );

And that's it !!
The onConfigurationChanged function should still be empty, or you can specialize it for your second activity.

Do you see another technique to handle different orientations with different devices ?


And my turn to ask a question :
How can we easily implement an isXLargeScreen method ? ( my current implementation is something I'm really proud of :) )




12 comments:

Anonymous said...

public static boolean isXLargeScreen(Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK)
>= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}

AndroidBlogger said...

It's that simple ?

Thank you 'Anonymous' !!

santilezica said...

@OP I was just thinking about this today! I find your full inheritance solution simple and elegant. Thanks for sharing!

@Anonymous nice implementation.

Bhavya said...

I found a very simple solution that works as far as I've tested it--
Just disable the orientation sensor on the phone!
Now when you launch the app, by default it starts in portrait mode on a phone and in landscape mode on a tablet, and thereon stays in that orientation.
Is there something I've overlooked or is it just that simple?

Anonymous said...

Great Post! I have some android source code for an app I developed that I'd like to sell. Can anybody suggests a site I can post my app for sale? I post on here: http://www.sellmyapplication.com

Anonymous said...

Sir, I don't think you need to do all that. All you have to do is create a layout-land folder and the proper xml for handling the landscape mode. I'm doing that it works perfectly ;-)

AndroidBlogger said...

@anonymous2 :
I already have two different set of Xmls, for landscape and portrait mode.
The point here is to force the tablet to use the landscape mode, and the phone to use the portrait mode.
And to switch off the orientation change capacity.

TDV said...

im a phone man myself, so I skimmed the tablet stuff. Regardless, Good post.

Sharma said...

hey i've started using andoid 4.03 but i'm unable to create an avd ! what should i do?

Sharma said...

hey i've started using andoid 4.03 but i'm unable to create an avd ! what should i do?

Sharma said...

hey i've started using andoid 4.03 but i'm unable to create an avd ! what should i do?

Anonymous said...

Thanks..The second way of your was excellent..Helped me a lot...Thanks Again..