Scaling fixes for Android devices in Phonegap

One of the most troubling issues I faced while working with Phonegap and a statically sized HTML application is scaling.  From the get-go my approach to scaling the HTML seemed like a hack and I was making use of viewports.  From my understanding this was/is a proper way to handle scaling an HTML page, but it seemed as though Phonegap has some other ideas about how to interpret that information on a Mobile device inside a Webview.  Firstly there is a property in the config.xml that enables the use of viewport scaling, which I did have enabled, however it seemed on certain devices as though the page was neglecting all the viewport information I had set.  What’s more I’m experiencing issues where when the keyboard slides open the scale for the application readjusts and no longer fits the screen.  This is even happening when I use “adjustPan” to not scale the application when the keyboard opens.

The solution to this ended up resulted in my splitting the code a bit between our Android and IOS builds a bit.  IOS continued to use it’s viewport with a minimum and maximum scale set.  The Android version however, required a little bit of java code to get working properly, but in the end works far better than the viewport did.

Credit for the solution can be given to the UIHacker blog here.  A little summary of what’s happening, using the native code to access the webview object (that is created to display your HTML) you can obtain the width and height of your view area and if you know the approximate width of your application (since we’re assuming it should fixed) you can calculate the scale value.  Using this newly calculated scale number you can set the initial scale of the webview itself and things will fit perfectly.  The only modification I have made to the code is to remove the deprecated getWidth() and getHeight() methods and replaced them with getSize().

// get actual screen size
     Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Int 
     int width = display.getWidth(); 
     int height = display.getHeight();

Even alterations, such as the keyboard opening will not mess things up.  There are some additional webview settings that can be updated to prevent the user from also manually pinch zooming the application, which can be seen with the following  lines.

this.appView.getSettings().setBuiltInZoomControls( false );
this.appView.getSettings().setSupportZoom( false );

Remaining code for posterity:

public class App extends DroidGap {
 
 // declare the original size of the iPad app
 protected float ORIG_APP_W = 768;
 protected float ORIG_APP_H = 1004;
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.loadUrl("file:///android_asset/www/index.html");
        
     // set some defaults
     this.appView.setBackgroundColor(0x000000);
     this.appView.setHorizontalScrollBarEnabled(false);
     this.appView.setHorizontalScrollbarOverlay(false);
     this.appView.setVerticalScrollBarEnabled(false);
     this.appView.setVerticalScrollbarOverlay(false);
     
     // get actual screen size
     Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
     int width = display.getWidth(); 
     int height = display.getHeight(); 
     
     // calculate target scale (only dealing with portrait orientation)
     double globalScale = Math.ceil( ( width / ORIG_APP_W ) * 100 );
     
     // make sure we're all good
     Log.v( "ORIG_APP_W", " = " + ORIG_APP_W );
     Log.v( "ORIG_APP_H", " = " + ORIG_APP_H );
     Log.v( "width", " = " + width );
     Log.v( "this.appView.getMeasuredHeight()", " = " + height );
     Log.v( "globalScale", " = " + globalScale );
     Log.v( "this.appView.getScale()", "index=" + this.appView.getScale() );
    
     // set some defaults on the web view
     this.appView.getSettings().setBuiltInZoomControls( false );
     this.appView.getSettings().setSupportZoom( false );
     this.appView.getSettings().setGeolocationEnabled( true );
     this.appView.getSettings().setLightTouchEnabled( true );
     this.appView.getSettings().setRenderPriority( RenderPriority.HIGH );
     
     // set the scale
     this.appView.setInitialScale( (int)globalScale );
   }
}

Manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.phonegap.testapp"
      android:versionCode="1"
      android:versionName="1.0">     
     
    <application android:icon="@drawable/icon" 
        android:label="@string/app_name"
        android:debuggable="true">
        <activity android:name=".App" 
                  android:label="Test App" 
                  android:configChanges="orientation|keyboardHidden"
                  android:noHistory="true" 
                  android:stateNotNeeded="true" 
                  android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 
    <!-- allows access to phonegap hardware features -->
 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 <!--<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />-->
 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
 
 
   <supports-screens
     android:largeScreens="true"
     android:normalScreens="false"
     android:smallScreens="false"
     android:resizeable="true"
     android:anyDensity="true"
     />
 
</manifest>

Layout main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >    
            <WebView android:id="@+id/appView"
            android:layout_height="fill_parent"
            android:layout_width="fill_parent"
            /> 
</LinearLayout>

1 Comment

    Thank you!

    • by Claudiu
    • 7:56 am, March 7, 2014
    • Reply

Leave a Reply to Claudiu Cancel reply