Android IU, Rotations, Persistence




CS175

Chris Pollett

Oct. 6, 2014

Outline

Introduction

Handling Rotations in Android

Handling Rotations in Android - cont'd

Rotation Example

portrait_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

<ImageView
    android:id ="@+id/my_photo"  
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:src="@drawable/myphoto"
	/>

<TextView
    android:id="@+id/textView" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="50"
    />

<SeekBar
    android:id="@+id/seekBar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    style="@android:style/Widget.ProgressBar.Horizontal"
    android:max="100"
    android:layout_marginRight="5dp" />

<!--  Dummy LinearLayout to prevent EditText from immediately hogging
      focus -->

<LinearLayout android:focusable="true"
 android:focusableInTouchMode="true" android:layout_width="0px"
 android:layout_height="0px" />

<EditText
    android:id="@+id/editText"
    android:layout_width="200px"
    android:layout_height="wrap_content"
    android:inputType="number" >

</EditText>


<CheckBox
    android:id="@+id/checkBox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Disable Edit Text" />


<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Toast Me" />


    
</LinearLayout>


landscape_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ImageView
    android:id ="@+id/my_photo"  
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:src="@drawable/myphoto"
	/>
<!--  notice the outer layout is horizontal and then we
have a vertical one next to the image, this shows we are
doing something different than the portrait layout case -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >
<TextView
    android:id="@+id/textView" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="50"
    />
<SeekBar
    android:id="@+id/seekBar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    style="@android:style/Widget.ProgressBar.Horizontal"
    android:max="100"
    android:layout_marginRight="5dp" />
<!--  Dummy LinearLayout to prevent EditText from immediately hogging
      focus -->
<LinearLayout android:focusable="true"
 android:focusableInTouchMode="true" android:layout_width="0px"
 android:layout_height="0px" />

<EditText
    android:id="@+id/editText"
    android:layout_width="200px"
    android:layout_height="wrap_content"
    android:inputType="number" >
</EditText>
<CheckBox
    android:id="@+id/checkBox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Disable Edit Text" />

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Toast Me" />
</LinearLayout>
    
</LinearLayout>

RotationActivity.java

package org.pollett.rotationcontrols;

import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

public class RotationActivity extends Activity 
    implements OnKeyListener, OnClickListener, OnSeekBarChangeListener 
{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Here is where we detect orientation and switch between them
        if(getResources().getConfiguration().orientation == 
        	Configuration.ORIENTATION_PORTRAIT) 
        {
        	 setContentView(R.layout.portrait_layout);
        }
        else
        {
       	     setContentView(R.layout.landscape_layout);       	
        }
        //Set programmatically the initial value of the TextView
        TextView textView = (TextView) this.findViewById( R.id.textView );
        textView.setText("25");

        /*
           To implement SeekBarChangeListener you have to implement three methods:
           onProgressChanged, onStartTrackingTouch, and onStopTrackingTouch
           We only care about the first
         */
        SeekBar seekBar = (SeekBar) this.findViewById(R.id.seekBar);
        seekBar.setOnSeekBarChangeListener(this);
        seekBar.setProgress(25);
 
        //our key listener is used to get the keyboard to go away
        EditText editText = (EditText) this.findViewById( R.id.editText );
        editText.setOnKeyListener(this);

        //Set up a listener to handle when the CheckBox is checked/unchecked
        CheckBox checkBox = (CheckBox)this.findViewById( R.id.checkBox );
        checkBox.setOnClickListener(this);
        
        View clickMeButton = this.findViewById( R.id.button );
        /* Clicking on the button displays a toast message.
           These messages can be useful for debugging.
         */
        clickMeButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
            	Toast.makeText( getApplicationContext(), 
            			"This is an Informational Toast Message", 
            			Toast.LENGTH_LONG).show();
            }
        });
    }
    @Override
    /** 
       The code below is used to get rid of the keyboard when entered clicked
    */
    public boolean onKey(View v, int keyCode, KeyEvent event)
    {
        // If the event is a key-down event on the "enter" button
        if ((event.getAction() == KeyEvent.ACTION_DOWN)
                && (keyCode == KeyEvent.KEYCODE_ENTER)) {
            return true;
        }
        return false;
    }
    @Override
    /**
       Handles changes to the CheckBox. If checked we disable the
       EditText area; otherwise, we enable it

       @param v - view that event is coming from
    */
    public void onClick(View v)
    {
        EditText editText = (EditText) this.findViewById( R.id.editText );
        CheckBox checkBox = (CheckBox)this.findViewById( R.id.checkBox );
        if(checkBox.isChecked()) {
        	editText.setEnabled(false);
            TextView textView = (TextView) this.findViewById( R.id.textView );
            textView.setText(editText.getText());
            int num = Integer.parseInt(editText.getText().toString());
            if(num > 100) {
            	num = 100;
            } else if (num < 0) {
            	num = 0;
            }
            SeekBar seekBar= (SeekBar) this.findViewById( R.id.seekBar) ;
            seekBar.setProgress(num);
        } else {
        	editText.setEnabled(true);
        }
    } 
    @Override
    /** 
       Here where we handle SeekBar events. Changes to the SeekBar are
       converted to a number and displayed in the TextView
     */
    public void onProgressChanged (SeekBar seekBar, int progress, boolean fromUser) {
    	TextView textView = (TextView) this.findViewById( R.id.textView );    	
    	textView.setText("" + progress);
    }
    @Override
    public void onStartTrackingTouch (SeekBar seekBar) 
    {
    }
    @Override    
    public void onStopTrackingTouch (SeekBar seekBar) {
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}


AndroidManifest.xml

Since we are using a different activity name than the default, I thought I'd include this so that people remember they would need to modify it:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.pollett.rotationcontrols"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="20" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".RotationActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Android Rotation App Screenshots

Image of rotation app in portrait mode
Image of rotation app in landscape mode

Quiz

Which of the following is true?

  1. Every Javascript Object has a prototype property which can be used to detect the screen orientation of the enclosing scope.
  2. Storyboard constraints for rotations are always specified programmatically outside of Interface Builder.
  3. To change the screen's controls when the UI changes orientation in iPhone we can override willAnimateRotationToInterfaceOrientation and given rectangle coordinates for the new control sizes and locations.

Logging

Logging Example

Storing and Retrieving Data

Using Preferences

More on Using Preferences

Our Story So Far...

iPhone Filesystem Test

Android FileSystem Test (Read Part)

Android FileSystem Test (Write Part)

FileOutputStream fos = null;
try
{
   fos = this.openFileOutput("filename.txt", Context.MODE_PRIVATE);
   fos.write("hi there\n".getBytes());
   Log.i("AndroidPersistence", "I just wrote stuff\n");
}
catch (IOException ie)
{
   Log.e("AndroidPersistence", "File Write Error");
}
finally
{
   if(fos !=null) 
   {
      try {fos.close();} catch(Exception e) {}
   }
}

SQLite

Database Commands

SQLite on the iPhone

Executing Commands on an SQLite Database on the iPhone

Android Database Persistence

On Testing Code

Subclassing SQLiteOpenHelper