'개발/모바일OS(안드로이드,아이폰,윈도모바일등)'에 해당되는 글 59건

  1. 2010.03.30 서비스 등록 7
  2. 2010.03.26 안드로이드 폰 화면 사이즈 구하기
  3. 2010.03.23 Understanding User Interface in Android - Part 2: Views 7
  4. 2010.03.23 Dialog App
  5. 2010.03.16 안드로이드 AVD SDcard Mount 방법
  6. 2010.02.10 안드로이드 에뮬레이터 host 수정법 4
  7. 2010.02.04 자료 보관할 내용. 1
  8. 2010.02.03 안드로이드 위젯에서 Activity 호출하기. 17
  9. 2010.02.02 How to make a simple Android widget 5
  10. 2010.01.28 Using Google Maps in Android 63
2010. 3. 30. 10:19

서비스 등록





<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>


  <receiver android:name=".service.MyStartupIntentReceiver">
            <intent-filter>
           
              <action android:name="android.intent.action.BOOT_COMPLETED" /> 
              <category android:name="android.intent.category.HOME" />
            </intent-filter>
        </receiver>       
  <service android:name=".service.MyService">
     <intent-filter>
       <action android:name=".service.MyService" />
     </intent-filter>
    </service>    

package com.qnsolv.android.lifelog7.service;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class MyStartupIntentReceiver extends BroadcastReceiver {

 public void onReceive(Context context, Intent intent) {
  if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
   Log.w("lifeLog", " MyStartupIntentReceiver  ");

   Intent serviceIntent = new Intent();
   serviceIntent.setAction(".service.MyService");
   context.startService(serviceIntent);
  }
 }
}

package com.qnsolv.android.lifelog7.service;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {
 private Timer timer;
 private TimerTask executeAgain = new TimerTask() {
  @Override
  public void run() {
   Log.i("shservice", "!!!!!!!!!!!!!!");
   ContentResolver cr = getContentResolver();
   try{
    LocationManager locationManager;
    Log.i("shservice", "!!!!!!!!!!!!!!2");
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    Log.i("shservice", "!!!!!!!!!!!!!!3");
    Location location = locationManager
      .getLastKnownLocation(LocationManager.GPS_PROVIDER);
    Log.i("shservice", "!!!!!!!!!!!!!!4");
    Log.i("shservice", "!!!!!!!!!!!!!!5" + location);
    String latLongString;

    if (location != null) {
     double lat = location.getLatitude();
     double lng = location.getLongitude();
     latLongString = "Lat:" + lat + "\nLong:" + lng;
    } else {
     latLongString = "No location found";
    }

    Log.i("shservice", "!!!!!!!!!!!!!!6= "+latLongString);
    System.out.println("latLongString=="+latLongString);
    // Do something
   }catch(Exception e){
    e.printStackTrace();
    System.out.println();
    
   }

  }
 };

 @Override
 public void onStart(Intent intent, int startId) {
  if (timer == null) {
   timer = new Timer("Alert timer");
  }

  timer.scheduleAtFixedRate(executeAgain, 0, 10000);

 }

 @Override
 public void onDestroy() {
  this.stopSelf();
  Log.i("AlertService", "AlertService is being destroyed!!!");
 }

 @Override
 public void onCreate() {
  timer = new Timer("Alert timer");
 }

 @Override
 public IBinder onBind(Intent arg0) {
  return null;
 }
}

2010. 3. 26. 15:12

안드로이드 폰 화면 사이즈 구하기





폰 사이즈 구하기는 그냥 숫자만 봐도 알겠는데..

PixeFormat에 관련된 숫자가 의미하는건 모르겠다 -_-;;

view plaincopy to clipboardprint?
    Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();  
    int displayWidth = display.getWidth();  
    int displayHeight = display.getHeight();  
    int displayOrientation = display.getOrientation();  
    int displayPixelFormat = display.getPixelFormat();  
    float displayRefreshRate = display.getRefreshRate();  
      
 
    System.out.println("displayWidth : " + displayWidth);  
    System.out.println("displayHeight : " + displayHeight);  
    System.out.println("displayOrientation : " + displayOrientation);  
    System.out.println("displayPixelFormat : " + displayPixelFormat);  
    System.out.println("displayRefreshRate : " + displayRefreshRate);  
      
//  결과  
//  displayWidth : 240  
//  displayHeight : 400  
//  displayOrientation : 0      //0:세로, 1: 가로  
//  displayPixelFormat : 4      // ??  
//  displayRefreshRate : 60.0 

2010. 3. 23. 15:58

Understanding User Interface in Android - Part 2: Views





In the previous article on Android UI you saw the components that make up the UI of an Android application. The basic unit of the Android UI is the View. A View represents a widget that has an appearance on the screen. In this article (and the next two), you will learn about the various common views that you would likely use in your journey of Android development. In particular, I have categorized the views in this series into the following group:

  • Basic Views - commonly-used views such as TextView, EditText, and Button views
  • Picker Views - views that allows users to select from, such as the TimePicker and DatePicker views
  • List Views - views that display a long list of items, such as the ListView and the Spinner views
  • Display Views - views that display images, such as the Gallery and ImageSwitcher views
  • Menus - views that displays additional and context sensitive menu items
  • Additional Views - interesting views such as the AnalogClock and DigitalClock views

In this article, I will cover the first group - Basic Views. The next article will cover the Picker Views and List Views. Lastly, the third article will cover the Menus and additional views.
For all the examples in this article, you shall create a new Android project using Eclipse. Name the project as shown in Figure 1.


Figure 1 Naming your project

Basic Views

In this section, you will examine the basic views in Android that allow you to display text information as well as perform some basic selection. In particular, you will learn about the following views:

  • TextView
  • EditText
  • Button
  • ImageButton
  • CheckBox
  • ToggleButton
  • RadioButton
  • RadioGroup

TextView View

When you create a new Android project, Eclipse always creates the main.xml file (located in the res/layout folder) containing a <TextView> element:

<?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"
    >
 
    <TextView  
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="@string/hello"
        />
 
</LinearLayout>

The TextView view is used to display text to the user. This is the most basic view that you will definitely come across when you develop Android applications. If you need to allow users to edit the text displayed, you should use the subclass of TextView - EditText, which is discussed in the next section.
Button, ImageButton, EditText, CheckBox, ToggleButton, RadioButton, and RadioGroup Views
Besides the TextView view, which you will come across the most often, there are some other basic controls that you will find yourself using very often. They are: Button, ImageButton, EditText, CheckBox, ToggleButton, RadioButton, and RadioGroup.
First, add a new file to the res/layout folder and name it as basicviews.xml. Populate it with the following elements:

<?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"
    >
 
    <Button android:id="@+id/btnSave"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="Save"
        />
    <Button android:id="@+id/btnOpen"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:text="Open"
        />        
    <ImageButton android:id="@+id/btnImg1"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"        
        android:src="@drawable/icon"
        />
    <EditText android:id="@+id/txtName"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        />
    <CheckBox android:id="@+id/chkAutosave"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="Autosave"
        />  
    <CheckBox android:id="@+id/star" 
        style="?android:attr/starStyle" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        />                     
 
    <RadioGroup android:id="@+id/rdbGp1"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:orientation="vertical"
        >               
        <RadioButton android:id="@+id/rdb1"
            android:layout_width="fill_parent" 
            android:layout_height="wrap_content"
            android:text="Option 1"
            />
        <RadioButton android:id="@+id/rdb2"
            android:layout_width="fill_parent" 
            android:layout_height="wrap_content"        
            android:text="Option 2"
            />   
    </RadioGroup>
 
    <ToggleButton android:id="@+id/toggle1" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        /> 
 
</LinearLayout>

Note that you use the id attribute to identify each view. The id of a view must start with the "@+id/" specifier followed by the name of the view.
The above XML file contains the following views:

  • Button - represents a push-button widget
  • ImageButton - similar to the Button view, except that it also displays an image
  • EditText - a subclass of the TextView view, except that it allows users to edit its text content
  • CheckBox - a special type of button that has two states - checked or unchecked
  • RadioGroup and RadioButton - the RadioButton has two states - either checked or unchecked. Once a RadioButton is checked, it cannot be unchecked. A RadioGroup is used to group together one or more RadioButton views, thereby allowing only one RadioButton to be checked within the RadioGroup
  • ToggleButton - displays checked/unchecked states using a light indicator

Figure 2 shows how the various views will look like in their various states. In particular, the right side of the figure shows the CheckBox, RadioButton, and ToggleButton views in their checked state.


Figure 2 Various views in their various states

To handle the various common events associated with the various views, add a new class to the src/net.learn2develop.AndroidViews folder and name it as BasicViewsExample.java. Code its content as follows:

package net.learn2develop.AndroidViews;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.RadioGroup;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.widget.RadioGroup.OnCheckedChangeListener;
 
public class BasicViewsExample extends Activity 
{
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.basicviews);
 
        //---Button view---
        Button btnOpen = (Button) findViewById(R.id.btnOpen);
        btnOpen.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Toast.makeText(getBaseContext(), 
                        "You have clicked the Open button", 
                        Toast.LENGTH_SHORT).show();
            }
        });
 
        Button btnSave = (Button) findViewById(R.id.btnSave);
        btnSave.setOnClickListener(new View.OnClickListener() 
        {
            public void onClick(View v) {
                DisplayToast("You have clicked the Save button");
            }
        });
 
        //---CheckBox---
        CheckBox checkBox = (CheckBox) findViewById(R.id.chkAutosave);
        checkBox.setOnClickListener(new View.OnClickListener() 
        {
            public void onClick(View v) {
                if (((CheckBox)v).isChecked()) 
                    DisplayToast("CheckBox is checked");
                else
                    DisplayToast("CheckBox is unchecked");            
            }
        });
 
        //---RadioButton---
        RadioGroup radioGroup = (RadioGroup) findViewById(R.id.rdbGp1);        
        radioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() 
        {
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                //---displays the ID of the RadioButton that is checked---
                DisplayToast(Integer.toString(checkedId));
            }
        });
 
        //---ToggleButton---
        ToggleButton toggleButton = (ToggleButton) findViewById(R.id.toggle1);
        toggleButton.setOnClickListener(new View.OnClickListener() 
        {
            public void onClick(View v) {
               if (((ToggleButton)v).isChecked())
                    DisplayToast("Toggle button is On");
               else
                   DisplayToast("Toggle button is Off");
            }
        });
    }
 
    private void DisplayToast(String msg)
    {
         Toast.makeText(getBaseContext(), msg, 
                 Toast.LENGTH_SHORT).show();        
    }    
}

In particular, the above program displays a message (using the Toast class) when the various controls are clicked.
Add the following lines in bold to the AndroidManifest.xml file to register the new BasicViewsExample activity:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="net.learn2develop.AndroidViews"
      android:versionCode="1"
      android:versionName="1.0.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".ViewsActivity" 
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>        
 
        <activity android:name=".BasicViewsExample"
                  android:label="@string/app_name" />
 
    </application>
</manifest>

To display the BasicViewsExample activity, insert the following statements in bold in the ViewsActivity.java file:

package net.learn2develop.AndroidViews;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
 
public class ViewsActivity extends Activity 
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);        
 
        //---load the BasicViewsExample activity---
        startActivity(new Intent(this, BasicViewsExample.class));
 
    }
}

To test the application, press F11 to debug the application on the Android emulator. Figure 3 shows the message displayed when the ToggleButton is clicked.


Figure 3 Message displayed when ToggleButton is clicked

For the EditText view, you can also set it to accept passwords by replacing each character with a ".". This is done using the password attribute:

<EditText android:id="@+id/txtName"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:password = "true"
        />

Figure 4 shows that when you enter a string of text into the view, the character you enter always appears first and then changes into a "." when you enter the next character (or after one second if you do nothing).


Figure 4 With android:password attribute set to true

ProgressBar View

The ProgressBar view provides visual feedback of some background tasks. For example, you might be downloading some data from the web and need to update the user of the status of the download. In this case, the ProgressBar view is a good choice for this task.
Using the same activity created in the previous section, insert the following element in the basicviews.xml file:

<?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"
    >    
 
    <ProgressBar android:id="@+id/progressbar"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"         
        />
 
    <Button android:id="@+id/btnSave"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="Save"
        />
    <!-
        Other views omitted
    -->
</LinearLayout>

The default mode of the ProgressBar view is indeterminate - that is, it shows a cyclic animation. This mode is useful for tasks that do not have a clear indication of when they will be completed. For example, you are sending some data to a web service and waiting for the server to respond.
The following code shows how you can spin off a background thread to simulate performing some long lasting tasks. When the task is completed, you hide the ProgressBar view by setting its Visibility property to GONE (value 8).

 
import android.widget.ProgressBar;
import android.os.Handler;
 
public class BasicViewsExample extends Activity 
{    
    private static int progress = 0;
    private ProgressBar progressBar;
    private int progressStatus = 0;
    private Handler handler = new Handler();
 
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.basicviews);
 
        progressBar = (ProgressBar) findViewById(R.id.progressbar);
 
        //---do some work in background thread---
        new Thread(new Runnable() 
        {
            public void run() 
            {
                //---do some work here---
                while (progressStatus < 10) 
                {
                    progressStatus = doSomeWork();
                }
 
                //---hides the progress bar---
                handler.post(new Runnable() 
                {
                    public void run() 
                    {
                        //---0 - VISIBLE; 4 - INVISIBLE; 8 - GONE---
                        progressBar.setVisibility(8);
                    }
                });
            }    
 
            //---do some long lasting work here---
            private int doSomeWork() 
            {
                try {
                    //---simulate doing some work---
                    Thread.sleep(500);
                } catch (InterruptedException e) 
                {
                    e.printStackTrace();
                }
                return ++progress;
            }
 
        }).start();  
 
        //...
        //...
    }
 
    //...
}

The difference between the INVISIBLE and GONE constants is that the INVISIBLE constant simply hides the ProgressBar view. The GONE constant removes the ProgressBar view from the activity and does not take up any space on the activity.
The left of Figure 5 shows the ProgressBar view in action. When the background task is completed, the space taken by the view is given up when you set its Visibility property to GONE.


Figure 5 Progressbar view in action (left), disappears when the the background task is completed (right)

If you do not want to display the ProgressBar view in indeterminate mode, you can modify it to display as a horizontal bar. The following style attribute specifies the ProgressBar view to be displayed as a horizontal bar:

    <ProgressBar android:id="@+id/progressbar"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        style="?android:attr/progressBarStyleHorizontal"
        />

The following code causes the ProgressBar view to increment from 1 to 100 and then disappears off the screen (see also Figure 6):

public class BasicViewsExample extends Activity 
{    
    private static int progress = 0;
    private ProgressBar progressBar;
    private int progressStatus = 0;
    private Handler handler = new Handler();
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.basicviews);
 
        progressBar = (ProgressBar) findViewById(R.id.progressbar);
 
        //---do some work in background thread---
        new Thread(new Runnable() 
        {
            public void run() 
            {
                while (progressStatus < 100) 
                {
                    progressStatus = doSomeWork();
 
                    //---Update the progress bar---
                    handler.post(new Runnable() 
                    {
                        public void run() {
                            progressBar.setProgress(progressStatus);
                        }
                    });
 
                }
                //---hides the progress bar---
                handler.post(new Runnable() 
                {
                    public void run() {
                        //---0 - VISIBLE; 4 - INVISIBLE; 8 - GONE---
                        progressBar.setVisibility(8);
                    }
                });
            }    
 
            private int doSomeWork() 
            {
                try 
                {
                    //---simulate doing some work---
                    Thread.sleep(500);
                } catch (InterruptedException e) 
                {
                    e.printStackTrace();
                }
                return ++progress;
            }
 
        }).start();  
 
        //...
        //...
    }
}


Figure 6 Horizontal Progressbar view in action (left), disappears when the the background task is completed (right)

AutoCompleteTextView View

The AutoCompleteTextView view is a view that is similar to the EditText view (in fact it is a subclass of the EditText view), except that it shows a list of completion suggestions automatically while the user is typing.
Add a new file to the res/layout folder and name it as autocomplete.xml and populate it with the following elements:

<?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"
    >
    <AutoCompleteTextView android:id="@+id/txtCountries"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        />                   
</LinearLayout>

Add a new file to the src/net.learn2develop.AndroidViews folder and name it as AutoCompleteExample.java. Populate it as follows:

package net.learn2develop.AndroidViews;
 
import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
 
public class AutoCompleteExample extends Activity
{
    String[] presidents = 
    {
            "Dwight D. Eisenhower",
            "John F. Kennedy",
            "Lyndon B. Johnson",
            "Richard Nixon",
            "Gerald Ford",
            "Jimmy Carter",
            "Ronald Reagan",
            "George H. W. Bush",
            "Bill Clinton",
            "George W. Bush",
            "Barack Obama"
    };
 
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.autocomplete);
 
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_dropdown_item_1line, presidents);
 
        AutoCompleteTextView textView = (AutoCompleteTextView)
                findViewById(R.id.txtCountries);
        textView.setThreshold(3);
        textView.setAdapter(adapter);         
    }
}

Note that the list of suggestions is obtained from an ArrayAdapter object. The setThreshold() method sets the number of minimum number of characters the user must type before the suggestions appear as a drop-down menu.
Add the following lines in bold to the AndroidManifest.xml file to register the new AutoCompleteExample activity:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="net.learn2develop.AndroidViews"
      android:versionCode="1"
      android:versionName="1.0.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".ViewsActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
        <activity android:name=".AutoCompleteExample"
                  android:label="@string/app_name" />
 
    </application>
</manifest>

Modify the ViewsActivity.java file to start the AutoCompleteExample activity:

package net.learn2develop.AndroidViews;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
 
public class ViewsActivity extends Activity 
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);      
 
        startActivity(new Intent(this, AutoCompleteExample.class));
 
    }
}

Figure 7 shows the AutoCompleteTextView view in action when you enter some text into it.


Figure 6 AutoCompleteTextView in action

Summary

In this article, you have seen some of the very common views that you will use in Android. In the next two articles, I will dive into more views that you can use in building your killer Android applications. Stay tuned for the next article, where I will discuss the various Picker and List views that you can use.

2010. 3. 23. 09:02

Dialog App





1. Activity를 Dialog화

   다양한 형태의 UI화면을 만들고 다이얼로그로 변경하는 방법  1) 기존 Activity를 만든다.


  2) AndroidManifest.xml에 Activity를 등록할때 다음 사항을 추가한다.

   android:theme="@android:style/Theme.Dialog"

  1. <activity 
  2. android:name=".dictionary.FindWord"
  3. android:theme="@android:style/Theme.Dialog"
  4. />

 

Dialog App 예제


Text OK Cancel
List
Progress Dialog
Radiobutton Dialog
Checkbok Dialog
Password Dialog

이런 Dialog은 


파일명: Layout

<?xml version="1.0" encoding="utf-8"?>

<!-- Demonstrates different uses of the android.app.AlertDialog.
     See corresponding Java code com.example.android.apis.app.AlertDialogSamples.java. -->

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/screen"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="fill_parent" android:layout_height="fill_parent"
        android:orientation="vertical">
        <Button android:id="@+id/two_buttons"
            android:layout_width="fill_parent" android:layout_height="wrap_content"
            android:text="@string/alert_dialog_two_buttons"/>
        <Button android:id="@+id/two_buttons2"
            android:layout_width="fill_parent" android:layout_height="wrap_content"
            android:text="@string/alert_dialog_two_buttons2"/>
        <Button android:id="@+id/select_button"
            android:layout_width="fill_parent" android:layout_height="wrap_content"
            android:text="@string/alert_dialog_select_button"/>
        <Button android:id="@+id/progress_button"
            android:layout_width="fill_parent" android:layout_height="wrap_content"
            android:text="@string/alert_dialog_progress_button"/>
        <Button android:id="@+id/radio_button"
            android:layout_width="fill_parent" android:layout_height="wrap_content"
            android:text="@string/alert_dialog_single_choice"/>
        <Button android:id="@+id/checkbox_button"
            android:layout_width="fill_parent" android:layout_height="wrap_content"
            android:text="@string/alert_dialog_multi_choice"/>
        <Button android:id="@+id/text_entry_button"
            android:layout_width="fill_parent" android:layout_height="wrap_content"
            android:text="@string/alert_dialog_text_entry"/>
    </LinearLayout>
</ScrollView>


파일명: AlertDialogSamples.java


package my.dia;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;


// 버턴을 상수값으로 지정했다. 
public class AlertDialogSamplesextends Activity{
    private static final int DIALOG_YES_NO_MESSAGE = 1;
    private static final int DIALOG_YES_NO_LONG_MESSAGE = 2;
    private static final int DIALOG_LIST = 3;
    private static final int DIALOG_PROGRESS = 4;
    private static final int DIALOG_SINGLE_CHOICE = 5;
    private static final int DIALOG_MULTIPLE_CHOICE = 6;
    private static final int DIALOG_TEXT_ENTRY = 7;

    private static final int MAX_PROGRESS = 100;
 
    private ProgressDialog mProgressDialog;
    private int mProgress;
    private Handler mProgressHandler;

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {

        case DIALOG_YES_NO_MESSAGE:

1yesnodialog.PNG

 


            return new AlertDialog.Builder(AlertDialogSamples.this)  //이너클래스 this는 안에것이기에 밖에 것의 this를 호출하기 AlertDialogSamples.this 이렇게 한다.
                .setIcon(R.drawable.alert_dialog_icon) //new한 객체.setIcon이렇게.. "."앞에는 AlertDialog.Builder이 있는 것이다.
 
                .setTitle(R.string.alert_dialog_two_buttons_title)  // "." 앞은 AlertDialog.Builder 이 있는 것이다.
// "." 앞은 AlertDialog.Builder 이 있는 것이다. setPositiveButton OK 버턴에 할당 확인 등등
// DialogInterface.OnClickListener 이것이 핸들러이다. 

                .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() { 
                    public void onClick(DialogInterface dialog, int whichButton) {
// 버턴클릭되었을때 처리할 내용 입력
                        /* User clicked OK so do some stuff */
                    }
                })
// "." 앞은 AlertDialog.Builder 이 있는 것이다. setPositiveButton취소 버턴이 할당
//
                . setPositiveButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {  
                    public void onClick(DialogInterface dialog, int whichButton) {

                        /* User clicked Cancel so do some stuff */
                    }
                })
                .create();
        case DIALOG_YES_NO_LONG_MESSAGE:

2text.PNG

 


            return new AlertDialog.Builder(AlertDialogSamples.this)
                .setIcon(R.drawable.alert_dialog_icon)
                .setTitle(R.string.alert_dialog_two_buttons_msg)
                .setMessage(R.string.alert_dialog_two_buttons2_msg)
                .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
 
                        /* User clicked OK so do some stuff */
                    }
                })
                .setNeutralButton(R.string.alert_dialog_something, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {

                        /* User clicked Something so do some stuff */
                    }
                })
                .setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {

                        /* User clicked Cancel so do some stuff */
                    }
                })
                .create();

        case DIALOG_LIST:

3list.PNG

 


            return new AlertDialog.Builder(AlertDialogSamples.this)
                .setTitle(R.string.select_dialog)
                .setItems(R.array.select_dialog_items, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {

                        /* User clicked so do some stuff */
                        String[] items = getResources().getStringArray(R.array.select_dialog_items);  // R.array.xml에 관련 내용이 등록되어 있음
                        new AlertDialog.Builder(AlertDialogSamples.this)
                                .setMessage("You selected: " + which + " , " + items[which])  // which값이 선택되어져서 오고 출력한다.
                                .show();
                    }
                })
                .create();

        case DIALOG_PROGRESS:

4progress.PNG

 


            mProgressDialog = new ProgressDialog(AlertDialogSamples.this);
            mProgressDialog.setIcon(R.drawable.alert_dialog_icon);
            mProgressDialog.setTitle(R.string.select_dialog);
            mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            mProgressDialog.setMax(MAX_PROGRESS);  //Max값 100
// setButton을 추가한 만큼 버턴은 추가될 수 있다. 
            mProgressDialog.setButton(getText(R.string.alert_dialog_hide), new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {

                    /* User clicked Yes so do some stuff */
                }
            });
            mProgressDialog.setButton2(getText(R.string.alert_dialog_cancel), new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {

                    /* User clicked No so do some stuff */
                }
            });
            return mProgressDialog;

        case DIALOG_SINGLE_CHOICE:

5single.PNG

 


            return new AlertDialog.Builder(AlertDialogSamples.this)
                .setIcon(R.drawable.alert_dialog_icon)
                .setTitle(R.string.alert_dialog_single_choice)
                .setSingleChoiceItems(R.array.select_dialog_items2, 0, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {

                        /* User clicked on a radio button do some stuff */
                    }
                })
                .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {

                        /* User clicked Yes so do some stuff */
                    }
                })
                .setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {

                        /* User clicked No so do some stuff */
                    }
                })
               .create();

        case DIALOG_MULTIPLE_CHOICE:

6repeat.PNG

 


            return new AlertDialog.Builder(AlertDialogSamples.this)
                .setIcon(R.drawable.ic_popup_reminder)
                .setTitle(R.string.alert_dialog_multi_choice)
                .setMultiChoiceItems(R.array.select_dialog_items3,
                        new boolean[]{false, true, false, true, false, false, false},
                        new DialogInterface.OnMultiChoiceClickListener() {
                            public void onClick(DialogInterface dialog, int whichButton,
                                    boolean isChecked) {

                                /* User clicked on a check box do some stuff */
                            }
                        })
                .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {

                        /* User clicked Yes so do some stuff */
                    }
                })
                .setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {

                        /* User clicked No so do some stuff */
                    }
                })
               .create();

        case DIALOG_TEXT_ENTRY:

7textentry(1).PNG

 


            // This example shows how to add a custom layout to an AlertDialog
            LayoutInflater factory = LayoutInflater.from(this);
            final View textEntryView = factory.inflate(R.layout.alert_dialog_text_entry, null);
            return new AlertDialog.Builder(AlertDialogSamples.this)
                .setIcon(R.drawable.alert_dialog_icon)
                .setTitle(R.string.alert_dialog_text_entry)
                .setView(textEntryView)
                .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
 
                        /* User clicked OK so do some stuff */
                    }
                })
                .setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {

                        /* User clicked cancel so do some stuff */
                    }
                })
                .create();
        }
        return null;
    }

    /**
     * Initialization of the Activity after it is first created.  Must at least
     * call {@link android.app.Activity#setContentView(int)} to
     * describe what is to be displayed in the screen.
     */
    @Override
protected void onCreate(Bundle savedInstanceState) {  // Activity에 의해서 첫 시작한다.
        super.onCreate(savedInstanceState);

        setContentView(R.layout.alert_dialog);
 
        /* Display a text message with yes/no buttons and handle each message as well as the cancel action */
        Button twoButtonsTitle = (Button) findViewById(R.id.two_buttons);
        twoButtonsTitle.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                showDialog(DIALOG_YES_NO_MESSAGE);  //상수값으로 어떤 것이 눌렸는지 구분해 준다. 이것을 부르는 순간에 onCreateDialog가 호출되어진다.
            }
        });
 
        /* Display a long text message with yes/no buttons and handle each message as well as the cancel action */
        Button twoButtons2Title = (Button) findViewById(R.id.two_buttons2);
        twoButtons2Title.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                showDialog(DIALOG_YES_NO_LONG_MESSAGE);
            }
        });
 
 
        /* Display a list of items */
        Button selectButton = (Button) findViewById(R.id.select_button);
        selectButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                showDialog(DIALOG_LIST);
            }
        });
 
        /* Display a custom progress bar */
        Button progressButton = (Button) findViewById(R.id.progress_button);
        progressButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                showDialog(DIALOG_PROGRESS); //프로그레스 값을 초기화하게 아래에 붙은다.
                mProgress = 0;
                mProgressDialog.setProgress(0);
                mProgressHandler.sendEmptyMessage(0);
            }
        });
 
        /* Display a radio button group */
        Button radioButton = (Button) findViewById(R.id.radio_button);
        radioButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                showDialog(DIALOG_SINGLE_CHOICE);
            }
        });
 
        /* Display a list of checkboxes */
        Button checkBox = (Button) findViewById(R.id.checkbox_button);
        checkBox.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                showDialog(DIALOG_MULTIPLE_CHOICE);
            }
        });
 
        /* Display a text entry dialog */
        Button textEntry = (Button) findViewById(R.id.text_entry_button);
        textEntry.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                showDialog(DIALOG_TEXT_ENTRY);
            }
        });
 
        mProgressHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (mProgress >= MAX_PROGRESS) {
                    mProgressDialog.dismiss();
                } else {
                    mProgress++;
                    mProgressDialog.incrementProgressBy(1);
                    mProgressHandler.sendEmptyMessageDelayed(0, 100);
                }
            }
        };
    }
}

파일명: arrary.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
          http://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<resources>
    <!-- Used in View/Spinner1.java -->
    <string-array name="colors">
        <item>red</item>
        <item>orange</item>
        <item>yellow</item>
        <item>green</item>
        <item>blue</item>
        <item>violet</item>
    </string-array>
 
    <!-- Used in View/Spinner1.java -->
    <string-array name="planets">
        <item>Mercury</item>
        <item>Venus</item>
        <item>Earth</item>
        <item>Mars</item>
        <item>Jupiter</item>
        <item>Saturn</item>
        <item>Uranus</item>
        <item>Neptune</item>
        <item>Pluto</item>
    </string-array>

    <!-- Used in App/SearchInvoke.java -->
    <string-array name="search_menuModes">
        <item>Search Key</item>
        <item>Menu Item</item>
        <item>Type-To-Search</item>
        <item>Disabled</item>
    </string-array>
 
    <!-- Used in app/dialog examples -->
    <string-array name="select_dialog_items">  //DIALOG_LIST에서 데이터를 가져가서 사용함
        <item>Command one</item>
        <item>Command two</item>
        <item>Command three</item>
        <item>Command four</item>
    </string-array>
 
    <string-array name="select_dialog_items2">
        <item>Map</item>
        <item>Satellite</item>
        <item>Traffic</item>
        <item>Street view</item>
    </string-array>
 
    <string-array name="select_dialog_items3">
        <item>Every Monday</item>
        <item>Every Tuesday</item>
        <item>Every Wednesday</item>
        <item>Every Thursday</item>
        <item>Every Friday</item>
        <item>Every Saturday</item>
        <item>Every Sunday</item>
    </string-array>
 
    <!-- Used in app/menu examples -->
    <string-array name="entries_list_preference">
        <item>Alpha Option 01</item>
        <item>Beta Option 02</item>
        <item>Charlie Option 03</item>  
    </string-array>

    <!-- Used in app/menu examples -->
    <string-array name="entryvalues_list_preference">
        <item>alpha</item>
        <item>beta</item>
        <item>charlie</item>  
    </string-array>
 
</resources>

파일명: R.String.xml


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, MyActivity!</string>
    <string name="app_name">MyDialogApp</string>
    <string name="activity_dialog">App/Activity/Dialog</string>
    <string name="dialog_activity_text">Example of how you can use the
            Theme.Dialog theme to make an activity that looks like a
            dialog.</string>

    <string name="activity_custom_dialog">App/Activity/Custom Dialog</string>
    <string name="custom_dialog_activity_text">Example of how you can use a
            custom Theme.Dialog theme to make an activity that looks like a
            customized dialog, here with an ugly frame.</string>
               <!-- ============================== -->
    <!--  app/dialog examples strings  -->
    <!-- ============================== -->

    <string name="activity_alert_dialog">App/Dialog</string>
    <string name="alert_dialog_two_buttons">OK Cancel dialog with a message</string>
    <string name="alert_dialog_two_buttons2">OK Cancel dialog with a long message</string>
    <string name="alert_dialog_select_button">List dialog</string>
    <string name="alert_dialog_single_choice">Single choice list</string>
    <string name="alert_dialog_multi_choice">Repeat alarm</string>
    <string name="alert_dialog_progress_button">Progress dialog</string>
    <string name="alert_dialog_text_entry">Text Entry dialog</string>
    <string name="alert_dialog_username">Name:</string>
    <string name="alert_dialog_password">Password:</string>
    <string name="alert_dialog_two_buttons_title">
        Lorem ipsum dolor sit aie consectetur adipiscing\nPlloaso mako nuto
        siwuf cakso dodtos anr koop.
    </string>
    <string name="alert_dialog_two_buttons_msg">Header title</string>
    <string name="alert_dialog_two_buttons2_msg">
        Plloaso mako nuto siwuf cakso dodtos anr koop a
        cupy uf cak vux noaw yerw phuno. Whag schengos, uf efed, quiel
        ba mada su otrenzr.\n\nSwipontgwook proudgs hus yag su ba dagarmidad.
        Plasa maku noga wipont trenzsa schengos ent kaap zux comy.\n\nWipont trenz
        kipg naar mixent phona. Cak pwico siructiun
        ruous nust apoply tyu cak Uhex sisulutiun munityuw uw dseg
    </string>
    <string name="alert_dialog_ok">OK</string>
    <string name="alert_dialog_hide">Hide</string>
    <string name="alert_dialog_something">Something</string>
    <string name="alert_dialog_cancel">Cancel</string>
    <string name="alert_dialog_progress_text1">34</string>
    <string name="alert_dialog_progress_text2">145/305 KB</string>

    <string name="select_dialog">Header title</string>
    <string name="select_dialog_show">List dialog</string>
 
</resources>


이후 강의 내용

알람 처리



package service.alarm;


import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.SystemClock;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import java.util.Calendar;

/**
 * Example of scheduling one-shot and repeating alarms.  See
 * {@link OneShotAlarm} for the code run when the one-shot alarm goes off, and
 * {@link RepeatingAlarm} for the code run when the repeating alarm goes off.
 * <h4>Demo</h4>
App/Service/Alarm Controller
 
<h4>Source files</h4>
<table class="LinkTable">
        <tr>
            <td class="LinkColumn">src/com.example.android.apis/app/AlarmController.java</td>
            <td class="DescrColumn">The activity that lets you schedule alarms</td>
        </tr>
        <tr>
            <td class="LinkColumn">src/com.example.android.apis/app/OneShotAlarm.java</td>
            <td class="DescrColumn">This is an intent receiver that executes when the
                one-shot alarm goes off</td>
        </tr>
        <tr>
            <td class="LinkColumn">src/com.example.android.apis/app/RepeatingAlarm.java</td>
            <td class="DescrColumn">This is an intent receiver that executes when the
                repeating alarm goes off</td>
        </tr>
        <tr>
            <td class="LinkColumn">/res/any/layout/alarm_controller.xml</td>
            <td class="DescrColumn">Defines contents of the screen</td>
        </tr>
</table>

 */
public class AlarmController extends Activity {
    Toast mToast;

    @Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.alarm_controller);

        // Watch for button clicks.
        Button button = (Button)findViewById(R.id.one_shot);
        button.setOnClickListener(mOneShotListener);
        button = (Button)findViewById(R.id.start_repeating);
        button.setOnClickListener(mStartRepeatingListener);
        button = (Button)findViewById(R.id.stop_repeating);
        button.setOnClickListener(mStopRepeatingListener);
    }

    private OnClickListener mOneShotListener = new OnClickListener() {
        public void onClick(View v) {
            // When the alarm goes off, we want to broadcast an Intent to our
            // BroadcastReceiver.  Here we make an Intent with an explicit class
            // name to have our own receiver (which has been published in
            // AndroidManifest.xml) instantiated and called, and then create an
            // IntentSender to have the intent executed as a broadcast.
            Intent intent = new Intent(AlarmController.this, OneShotAlarm.class);
            PendingIntent sender = PendingIntent.getBroadcast(AlarmController.this,
                    0, intent, 0);

            // We want the alarm to go off 30 seconds from now.
            Calendar calendar = Calendar.getInstance();  //켈린터 객체 세팅
            calendar.setTimeInMillis(System.currentTimeMillis()); // 현재 시간 세팅
            calendar.add(Calendar.SECOND, 30); // 30초를 추가한다 30초 후 진행

            // Schedule the alarm!
            AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);  // 메지저는 프레임이 가지고 있다. 
            am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);  // Set을 한다. 센더(인텐트)를 깨운다. 팬딩인텐트를 30초후에 깨운다. 불러줘라

            // Tell the user about what we did.
            if (mToast != null) {
                mToast.cancel();
            }
            mToast = Toast.makeText(AlarmController.this, R.string.one_shot_scheduled,   //일단 알람메니저에게 30초 깨우는 것 등록후 나는 토스트로 문자열을 뜨워줄 것이다. 
                    Toast.LENGTH_LONG);

 


            mToast.show();
8알람oneshot.PNG

 


        }
    };

    private OnClickListener mStartRepeatingListener= new OnClickListener() {
        public void onClick(View v) {
            // When the alarm goes off, we want to broadcast an Intent to our
            // BroadcastReceiver.  Here we make an Intent with an explicit class
            // name to have our own receiver (which has been published in
            // AndroidManifest.xml) instantiated and called, and then create an
            // IntentSender to have the intent executed as a broadcast.
            // Note that unlike above, this IntentSender is configured to
            // allow itself to be sent multiple times.
            Intent intent = new Intent(AlarmController.this, RepeatingAlarm.class);
            PendingIntent sender = PendingIntent.getBroadcast(AlarmController.this,
                    0, intent, 0);
 
            // We want the alarm to go off 30 seconds from now.
            long firstTime = SystemClock.elapsedRealtime();  // 부팅후 얼마의 시간 경과 시간을 뜻한다. 결국 현재 시간과 똑같다
            firstTime += 15*1000; // 밀리센컨드로 천을 콥하니 15초후를 구한 것이다. 

            // Schedule the alarm!
            AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);  // 알람 메니저를 꺼내서 set리피팅
            am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, // 반복해라라고 요청한다. 지금으로부터 15초후 15초 간경으로 센더(브로드케스팅)을 수행하게 된다.
                            firstTime, 15*1000, sender);

            // Tell the user about what we did.
            if (mToast != null) {  // 토스트가 널이 아니면 다시 시작해라
                mToast.cancel();
            }
            mToast = Toast.makeText(AlarmController.this, R.string.repeating_scheduled,
                    Toast.LENGTH_LONG);

            mToast.show();

9알람.PNG

 


        }
    };

    private OnClickListener mStopRepeatingListener= new OnClickListener() {
        public void onClick(View v) {
            // Create the same intent, and thus a matching IntentSender, for
            // the one that was scheduled.
            Intent intent = new Intent(AlarmController.this, RepeatingAlarm.class);
            PendingIntent sender = PendingIntent.getBroadcast(AlarmController.this,
                    0, intent, 0);
 
            // And cancel the alarm.
            AlarmManageram = (AlarmManager)getSystemService(ALARM_SERVICE);
            am.cancel(sender);

            // Tell the user about what we did.
            if (mToast != null) {
                mToast.cancel();
            }
            mToast = Toast.makeText(AlarmController.this, R.string.repeating_unscheduled,
                    Toast.LENGTH_LONG);
            mToast.show();
        }
    };
}

// 리시버는 종료가 필요하지 않다. 

package service.alarm;

import android.content.Context;
import android.content.Intent;
import android.content.BroadcastReceiver;
import android.widget.Toast;



/**
 * This is an example of implement an {@link BroadcastReceiver} for an alarm that
 * should occur once.
 * <p>
 * When the alarm goes off, we show a <i>Toast</i>, a quick message.
 */
public class OneShotAlarm extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        Toast.makeText(context, R.string.one_shot_received, Toast.LENGTH_SHORT).show();
    }
}

/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package service.alarm;

// Need the following import to get access to the app resources, since this
// class is in a sub-package.


import android.content.Context;
import android.content.Intent;
import android.content.BroadcastReceiver;
import android.widget.Toast;

/**
 * This is an example of implement an {@link BroadcastReceiver} for an alarm that
 * should occur once.
 */
public class RepeatingAlarmextends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {

        Toast.makeText(context, R.string.repeating_received, Toast.LENGTH_SHORT).show();  //여기에다 미디어 플레이 사용하면 소리가 나온다. 

10리피팅알람.PNG

 

//을 알람메니저가 이 onReceive를 호출해 주기때문에 토스트가 표시된 것이다.


    }
}

프리퍼런스

값을 수정해서 프로그램 종료하거나 전원을 off후 on하고 다시 실행해도 이전 값이 남아 있는다. xml에 값을 저장하게 된다.
재배포시에 아마도 지워 초기화 될 것이다.
이것은 UI 자체에 저장기능을 사용하는 것이다. 
 - preferencefrom xml java하나 가 돈다 이것이 저장하고 있는 것이다.
주로 체크박스에 많이 사용한다. 



AdvancedPreferences
DefaultValues
LaunchingPreferences
PreferenceDependencies
PreferencesFromCode

파일명: PreferencesFromXml


package my.pref;



import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;

public class PreferencesFromXml extends PreferenceActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        // Load the preferences from an XML resource
        addPreferencesFromResource(R.xml.preferences); //R에서 갔다 쓸 것이다.
    }

}

파일명: preferences.xml

<?xml version="1.0" encoding="utf-8"?>

<!-- This is a primitive example showing the different types of preferences available. -->
<PreferenceScreen
        xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory  // 이 것 처럼 일반 UI가 아니라 프리퍼런스UI를 사용해야만 값을 저장할 수 있는 것이다. 
//이것은    addPreferencesFromResource(R.xml.preferences); 으로부터 호출되어 지는 것이다.
            android:title="@string/inline_preferences">
 
        <CheckBoxPreference // 이 것을 사용해서 저장할 수 있는 것이다.
                android:key="checkbox_preference"
                android:title="@string/title_toggle_preference"
                android:summary="@string/summary_toggle_preference" />
 
    </PreferenceCategory>
 
    <PreferenceCategory
            android:title="@string/dialog_based_preferences">

        <EditTextPreference
                android:key="edittext_preference"
                android:title="@string/title_edittext_preference"
                android:summary="@string/summary_edittext_preference"
                android:dialogTitle="@string/dialog_title_edittext_preference" />
 
        <ListPreference
                android:key="list_preference"
                android:title="@string/title_list_preference"
                android:summary="@string/summary_list_preference"
                android:entries="@array/entries_list_preference"
                android:entryValues="@array/entryvalues_list_preference"
                android:dialogTitle="@string/dialog_title_list_preference" />

    </PreferenceCategory>

    <PreferenceCategory
            android:title="@string/launch_preferences">

        <!-- This PreferenceScreen tag serves as a screen break (similar to page break
             in word processing). Like for other preference types, we assign a key
             here so it is able to save and restore its instance state. -->
        <PreferenceScreen  // 이 것때문에 새로운 창이 뜨게 된다. 스크린안에 스크린을 넣었기에 새로운 창이 열리는 것이다. 
                android:key="screen_preference"
                android:title="@string/title_screen_preference"
                android:summary="@string/summary_screen_preference">
 
            <!-- You can place more preferences here that will be shown on the next screen. -->
 
            <CheckBoxPreference
                    android:key="next_screen_checkbox_preference"
                    android:title="@string/title_next_screen_toggle_preference"
                    android:summary="@string/summary_next_screen_toggle_preference" />
 
        </PreferenceScreen>

        <PreferenceScreen
                android:title="@string/title_intent_preference"
                android:summary="@string/summary_intent_preference">

            <intentandroid:action="android.intent.action.VIEW"    // 인텐트에 값을 넣어서 URL값을 전달한다. 
                    android:data="http://www.android.com" />

        </PreferenceScreen>

    </PreferenceCategory>
 
    <PreferenceCategory
            android:title="@string/preference_attributes">
 
        <CheckBoxPreference
                android:key="parent_checkbox_preference"
                android:title="@string/title_parent_preference"
                android:summary="@string/summary_parent_preference" />

        <!-- The visual style of a child is defined by this styled theme attribute. -->
        <CheckBoxPreference
                android:key="child_checkbox_preference"
                android:dependency="parent_checkbox_preference"
                android:layout="?android:attr/preferenceLayoutChild"
                android:title="@string/title_child_preference"
                android:summary="@string/summary_child_preference" />
 
    </PreferenceCategory>
 
</PreferenceScreen>

파일명: array.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
          http://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<resources>
    <!-- Used in View/Spinner1.java -->
    <string-array name="colors">
        <item>red</item>
        <item>orange</item>
        <item>yellow</item>
        <item>green</item>
        <item>blue</item>
        <item>violet</item>
    </string-array>
 
    <!-- Used in View/Spinner1.java -->
    <string-array name="planets">
        <item>Mercury</item>
        <item>Venus</item>
        <item>Earth</item>
        <item>Mars</item>
        <item>Jupiter</item>
        <item>Saturn</item>
        <item>Uranus</item>
        <item>Neptune</item>
        <item>Pluto</item>
    </string-array>

    <!-- Used in App/SearchInvoke.java -->
    <string-array name="search_menuModes">
        <item>Search Key</item>
        <item>Menu Item</item>
        <item>Type-To-Search</item>
        <item>Disabled</item>
    </string-array>
 
    <!-- Used in app/dialog examples -->
    <string-array name="select_dialog_items">
        <item>Command one</item>
        <item>Command two</item>
        <item>Command three</item>
        <item>Command four</item>
    </string-array>
 
    <string-array name="select_dialog_items2">
        <item>Map</item>
        <item>Satellite</item>
        <item>Traffic</item>
        <item>Street view</item>
    </string-array>
 
    <string-array name="select_dialog_items3">
        <item>Every Monday</item>
        <item>Every Tuesday</item>
        <item>Every Wednesday</item>
        <item>Every Thursday</item>
        <item>Every Friday</item>
        <item>Every Saturday</item>
        <item>Every Sunday</item>
    </string-array>
 
    <!-- Used in app/menu examples --> // 선택되면 보여지는 것이고 값을 수정하면 아랬것으로 저장한다. 
    <string-array name="entries_list_preference"> 
        <item>Alpha Option 01</item>
        <item>Beta Option 02</item>
        <item>Charlie Option 03</item>  
    </string-array>

    <!-- Used in app/menu examples -->   // 이것에 저장하겠다. 상기에 것은 보이는 것
    <string-array name="entryvalues_list_preference">
        <item>alpha</item>
        <item>beta</item>
        <item>charlie</item>  
    </string-array>
 
</resources>

데이터는 아래 위치에 저장된다.

11preference.PNG

 

2010. 3. 16. 11:17

안드로이드 AVD SDcard Mount 방법





개발을 위해서 Application 을 다운 받아서 설치하려고 했더니..

이게 왠일.. SDcard가 없다고 설치가 안된다고 나오더군요.

 

여기 저기 뒤져본 결과...

 

SDcard 이미지를 만들어서 환경설정에서 AVD 구동시 연결이 되게 하는 방법이 있더군요.

 

일단 SDcard 파일을 만들어야 합니다.

만드는 방법은...

Android SDK 를 설치를 했다면 SDK설치폴더\tools\ 에 보시면 mksdcard.exe 가 있습니다.

 

명령프롬프트로 해당 경로로 가셔서 아래와 같이 실행을 합니다.

 

mksdcard.exe -l sdcard 128M sdcard.iso

 

실행을 한 후 해당 폴더에 sdcard.iso 파일이 생성되어 있을 겁니다.

 

이제 이 SDcard 파일을 AVD와 연결하는게 남았습니다.

 

이클립스 메뉴에서 [Run] - [Run Configuration...] 아래와 같이 선택합니다.

 

위와 같이 메뉴를 클릭하면 아래와 같이 설정창이 뜹니다.

Additional Emulator Command Line Options

-sdcard SDcard파일 경로 를 입력합니다.

 

여기까지 하고 Run 하시면 SDcard가 있다고 나옵니다.

 

끝~

 

2010. 2. 10. 18:32

안드로이드 에뮬레이터 host 수정법




host 파일 수정 방법

remount 한다.
>adb remount

안드로이드에 있는 host 파일을 받는다.
>adb pull /system/etc/hosts D:\TDPlatform\android_home\backup\

hosts 파일 수정한다.
---------------------------------------
기본적으로 로컬만 등록되어 있음.
127.0.0.1      localhost
---------------------------------------

host 파일을 넣는다.
>adb push D:\TDPlatform\android_home\work\hosts /system/etc/

hosts 파일 수정 확인해보기
>adb -e shell
#cat /system/etc/hosts

2010. 2. 4. 18:41

자료 보관할 내용.




 * Copyright (C) 2009 The Android Open Source Project 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */ 
 
package com.example.android.wiktionary; 
 
import com.example.android.wiktionary.SimpleWikiHelper.ApiException; 
import com.example.android.wiktionary.SimpleWikiHelper.ParseException; 
 
import android.app.PendingIntent; 
import android.app.Service; 
import android.appwidget.AppWidgetManager; 
import android.appwidget.AppWidgetProvider; 
import android.content.ComponentName; 
import android.content.Context; 
import android.content.Intent; 
import android.content.res.Resources; 
import android.net.Uri; 
import android.os.IBinder; 
import android.text.format.Time; 
import android.util.Log; 
import android.widget.RemoteViews; 
 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 
 
/** 
 * Define a simple widget that shows the Wiktionary "Word of the day." To build 
 * an update we spawn a background {@link Service} to perform the API queries. 
 */ 
public class WordWidget extends AppWidgetProvider { 
    /** 
     * Regular expression that splits "Word of the day" entry into word 
     * name, word type, and the first description bullet point. 
     */ 
    public static final String WOTD_PATTERN = 
        "(?s)\\{\\{wotd\\|(.+?)\\|(.+?)\\|([^#\\|]+).*?\\}\\}"; 
 
    @Override 
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 
        Log.d("WordWidget.UpdateService", "onUpdate()"); 
        // To prevent any ANR timeouts, we perform the update in a service 
        context.startService(new Intent(context, UpdateService.class)); 
    } 
     
    public static class UpdateService extends Service { 
        @Override 
        public void onStart(Intent intent, int startId) { 
            Log.d("WordWidget.UpdateService", "onStart()"); 
 
            // Build the widget update for today 
            RemoteViews updateViews = buildUpdate(this); 
            Log.d("WordWidget.UpdateService", "update built"); 
             
            // Push update for this widget to the home screen 
            ComponentName thisWidget = new ComponentName(this, WordWidget.class); 
            AppWidgetManager manager = AppWidgetManager.getInstance(this); 
            manager.updateAppWidget(thisWidget, updateViews); 
            Log.d("WordWidget.UpdateService", "widget updated"); 
        } 
 
        @Override 
        public IBinder onBind(Intent intent) { 
            return null; 
        } 
         
        /** 
         * Build a widget update to show the current Wiktionary 
         * "Word of the day." Will block until the online API returns. 
         */ 
        public RemoteViews buildUpdate(Context context) { 
            // Pick out month names from resources 
            Resources res = context.getResources(); 
            String[] monthNames = res.getStringArray(R.array.month_names); 
             
            // Find current month and day 
            Time today = new Time(); 
            today.setToNow(); 
 
            // Build the page title for today, such as "March 21" 
            String pageName = res.getString(R.string.template_wotd_title, 
                    monthNames[today.month], today.monthDay); 
            String pageContent = null; 
             
            try { 
                // Try querying the Wiktionary API for today's word 
                SimpleWikiHelper.prepareUserAgent(context); 
                pageContent = SimpleWikiHelper.getPageContent(pageName, false); 
            } catch (ApiException e) { 
                Log.e("WordWidget", "Couldn't contact API", e); 
            } catch (ParseException e) { 
                Log.e("WordWidget", "Couldn't parse API response", e); 
            } 
             
            RemoteViews views = null; 
            Matcher matcher = null; 
             
                Prefs prefs = new Prefs(this); 
            if (pageContent == null) { 
                // could not get content, use cache 
                // could be null 
                pageContent = prefs.getPageContent(); 
            } 
             
            if (pageContent != null) { 
                // we have page content 
                // is it valid? 
                matcher = Pattern.compile(WOTD_PATTERN).matcher(pageContent); 
            } 
            if (matcher != null && matcher.find()) { 
                // valid content, cache it  
                // ensure that latest valid content is 
                // always cached in case of failures 
                prefs.setPageContent(pageContent); 
 
                // Build an update that holds the updated widget contents 
                views = new RemoteViews(context.getPackageName(), R.layout.widget_word); 
                 
                String wordTitle = matcher.group(1); 
                views.setTextViewText(R.id.word_title, wordTitle); 
                views.setTextViewText(R.id.word_type, matcher.group(2)); 
                views.setTextViewText(R.id.definition, matcher.group(3).trim()); 
                 
                // When user clicks on widget, launch to Wiktionary definition page 
                String definePage = String.format("%s://%s/%s", ExtendedWikiHelper.WIKI_AUTHORITY, 
                        ExtendedWikiHelper.WIKI_LOOKUP_HOST, wordTitle); 
                Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(definePage)); 
                PendingIntent pendingIntent = PendingIntent.getActivity(context, 
                        0 /* no requestCode */, defineIntent, 0 /* no flags */); 
                views.setOnClickPendingIntent(R.id.widget, pendingIntent); 
                 
            } else { 
                // Didn't find word of day, so show error message 
                views = new RemoteViews(context.getPackageName(), R.layout.widget_message); 
                views.setTextViewText(R.id.message, context.getString(R.string.widget_error)); 
            } 
            return views; 
        } 
    } 
} 

2010. 2. 3. 18:13

안드로이드 위젯에서 Activity 호출하기.




1. 호출 받을 Activity의 xml 파일 만들기. layout/appwidgetmain.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/LinearLayout01"
    android:layout_height="200dp"
    android:background="@drawable/background"
    android:layout_width="160dp"
    android:orientation="horizontal">
    <Button
     android:text="@+id/Button01"
     android:id="@+id/Button01"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content">
    </Button>
    <TextView
        android:id="@+id/widget_textview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical|center_horizontal"
        android:textColor="@android:color/black"
        android:text="17:12:34 PM"
        android:textSize="8pt"
    />
</LinearLayout>

호출 받을 Activity만들기
package com.sh.watchwidget;
import android.app.Activity;
import android.os.Bundle;
public class MyActvity extends Activity {
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
 
     // TODO Auto-generated method stub
 }
}


위젯의 배경 이미지 만들기 /res/drawable/background.png

위젯의 레이아웃 만들기 . layout/appwidgetmain.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/LinearLayout01"
    android:layout_height="200dp"
    android:background="@drawable/background"
    android:layout_width="160dp"
    android:orientation="horizontal">
    <Button
     android:text="@+id/Button01"
     android:id="@+id/Button01"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content">
    </Button>
    <TextView
        android:id="@+id/widget_textview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical|center_horizontal"
        android:textColor="@android:color/black"
        android:text="17:12:34 PM"
        android:textSize="8pt"
    />
</LinearLayout>


AppWidgetProvider를 상속 받은 위젯 메인 페이지 만들기.
package com.sh.watchwidget;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.widget.RemoteViews;
public class WatchWidget extends AppWidgetProvider
{
    @Override
    public void onUpdate( Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds )
    {
        RemoteViews remoteViews;
        ComponentName watchWidget;
        DateFormat format = SimpleDateFormat.getTimeInstance( SimpleDateFormat.MEDIUM, Locale.getDefault() );
        Intent intent = new Intent();
        intent.addCategory(Intent.CATEGORY_BROWSABLE);
        intent.setComponent(new ComponentName("com.sh.watchwidget", "com.sh.watchwidget.MyActvity"));
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
        remoteViews = new RemoteViews( context.getPackageName(), R.layout.appwidgetmain );
        watchWidget = new ComponentName( context, WatchWidget.class );
        remoteViews.setTextViewText( R.id.widget_textview, "Time = " + format.format( new Date()));
        remoteViews.setOnClickPendingIntent(R.id.Button01, pendingIntent);
        appWidgetManager.updateAppWidget( watchWidget, remoteViews );
       
       
    }
}

appwidget-provider xml 파일 만들기
<?xml version="1.0" encoding="utf-8" ?>
<appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="146dp"
    android:initialLayout="@layout/appwidgetmain"
    android:updatePeriodMillis="1000" 
    android:minHeight="144dp"/>

AndroidManifest.xml 파일에 application 추가하기

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sh.watchwidget"
    android:versionCode="1"
    android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
        <receiver android:name=".WatchWidget" android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/watch_widget_provider" />
        </receiver>
    <activity android:name="MyActvity"></activity>
</application>
    <uses-sdk android:minSdkVersion="3" />
</manifest>

결과 화면
 

소스를 보면 간단하지만 2일동안 삽질하여 만들 소스입니다.


아래는 아카이브 파일입니다.
2010. 2. 2. 09:21

How to make a simple Android widget





Yesterday I made my first Android widget. A very simple widget, just to try it out. It can show the time. No more, no less. I will here show you how to get started on widgets. I’ll start from scratch, so you actually don’t need any knowledge on Android development. Well, of course you need to have the SDK, and Eclipse installed and ready.

I used the 1.5 SDK, but it will probably work on newer SDK’s too.

I will show you how to do it in 6 easy steps.

 

1. Create a new Android project
Fire up Eclipse, and click File -> New -> Android project
Skærmbillede 2009-11-07 kl. 14.26.27
Type in a name for you project, eg. WatchWidget. Select the target, 1.5 in my case. I guess that there could be differences, so if you are not experienced in Android development, I suggest that you use 1.5 too.

Then we need an application name, which is the name that will show up on your phone. And last but not least, a package name.

Uncheck “Create activity”, as we don’t want any activities in this sample.

Click Finish to create the project. Now you have a structure that looks like this:

WatchWidget structure

 

2. Create the Java class
Right-click com.kasperholtze.watchwidget (or whatever you used for package name), and select New -> Class:

Create WatchWidget class

Give the class a name, i.e. WatchWidget. Then we need to extend the AppWidgetProvider, so type in android.appwidget.AppWidgetProvider as superclass, or browse for it.

Click Finish, and Eclipse will generate the following code:

package com.kasperholtze.watchwidget;

import android.appwidget.AppWidgetProvider;

public class WatchWidget extends AppWidgetProvider {

}

 

3. Create the Java code
Now it’s time to create our Java code, for updating the widget. Type in the following code:

package com.kasperholtze.watchwidget;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import com.kasperholtze.watchwidget.R;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.widget.RemoteViews;

public class WatchWidget extends AppWidgetProvider
{
    @Override
    public void onUpdate( Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds )
    {
        RemoteViews remoteViews;
        ComponentName watchWidget;
        DateFormat format = SimpleDateFormat.getTimeInstance( SimpleDateFormat.MEDIUM, Locale.getDefault() );

        remoteViews = new RemoteViews( context.getPackageName(), R.layout.main );
        watchWidget = new ComponentName( context, WatchWidget.class );
        remoteViews.setTextViewText( R.id.widget_textview, "Time = " + format.format( new Date()));
        appWidgetManager.updateAppWidget( watchWidget, remoteViews );
    }
}

The only method we use in this class, is onUpdate( Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds ), which we override from the AppWidgetProvider class.

First we create three objects. remoteViews, watchWidget and format. remoteViews is a reference to the main view, which we will create in a moment. watchWidget is a reference to our class, and format is the date format used to show the time.

Then we initialize the remoteViews and watchWidget. You will get an error one the line remoteViews.setTextViewText(), which is where we actually update the text on our widget, stating that R.id is not found, but that’s all right for now. We will create that one in a moment too.

appWidgetManager.updateAppWidget sets the RemoteViews that should be used for our widget.

 

4. Edit the view for our widget, main.xml
Using the UI designer takes some trying, testing and failing. If you have not tried this yet, you should try playing around with it. It takes some time to get the feeling of it.

My main.xml looks like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/LinearLayout01"
    android:layout_height="200dp"
    android:background="@drawable/background"
    android:layout_width="160dp"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/widget_textview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center_vertical|center_horizontal"
        android:textColor="@android:color/black"
        android:text="17:12:34 PM"
        android:textSize="8pt"
    />
</LinearLayout>

It contains a LinearLayout with a TextView inside. The important thing is the id of out TextView, which we used earlier in the WatchWidget class.
I used a standard widget background, which you can download at http://developer.android.com/guide/practices/ui_guidelines/widget_design.html. You can also grab it here:

WatchWidget background

Save it in the project, at res/drawable/background.png

 

5. Edit AndroidManifest.xml
The next thing is to edit the AndroidManifest.xml, which defines the application. We need to add an intent-filter, meta-data that defines which xml file we use for defining the widget provider, and name and other details of the application.

Here it goes…

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

    <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">

        <receiver android:name=".WatchWidget" android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/watch_widget_provider" />
        </receiver>

    </application>
   
    <uses-sdk android:minSdkVersion="3" />

</manifest>

 

6. Create widget provider
The last thing we have to do, before the application is ready to run, is to create a XML file, defining the widget provider. Create a new folder under res, called xml, and save the file as res/xml/watch_widget_provider.xml.

<?xml version="1.0" encoding="utf-8" ?>
<appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="146dp"
    android:initialLayout="@layout/main"
    android:updatePeriodMillis="1000"
    android:minHeight="144dp"/>

Here we set the minimum size that the widget needs to be added to a home screen. And then we set the updatePeriodMillis. updatePeriodMillis defines how often we wish to call the onUpdate method that we created earlier in the Java class.

That’s it! Connect your phone, or fire up a virtual device, and try it out

2010. 1. 28. 16:06

Using Google Maps in Android





Creating the Project

Using Eclipse, create a new Android project and name GoogleMaps as shown in Figure 1.


Figure 1 Creating a new Android project using Eclipse

Obtaining a Maps API key

Beginning with the Android SDK release v1.0, you need to apply for a free Google Maps API key before you can integrate Google Maps into your Android application. To apply for a key, you need to follow the series of steps outlined below. You can also refer to Google's detailed documentation on the process at http://code.google.com/android/toolbox/apis/mapkey.html.

First, if you are testing the application on the Android emulator, locate the SDK debug certificate located in the default folder of "C:\Documents and Settings\<username>\Local Settings\Application Data\Android". The filename of the debug keystore is debug.keystore. For deploying to a real Android device, substitute the debug.keystore file with your own keystore file. In a future article I will discuss how you can generate your own keystore file.

For simplicity, copy this file (debug.keystore) to a folder in C:\ (for example, create a folder called "C:\Android").

Using the debug keystore, you need to extract its MD5 fingerprint using the Keytool.exe application included with your JDK installation. This fingerprint is needed to apply for the free Google Maps key. You can usually find the Keytool.exe from the "C:\Program Files\Java\<JDK_version_number>\bin" folder.

Issue the following command (see also Figure 2) to extract the MD5 fingerprint.

keytool.exe -list -alias androiddebugkey -keystore "C:\android\debug.keystore" -storepass
 android -keypass android

Copy the MD5 certificate fingerprint and navigate your web browser to: http://code.google.com/android/maps-api-signup.html. Follow the instructions on the page to complete the application and obtain the Google Maps key.


Figure 2 Obtaining the MD5 fingerprint of the debug keystore

To use the Google Maps in your Android application, you need to modify your AndroidManifest.xml file by adding the <uses-library> element together with the INTERNET permission:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="net.learn2develop.GoogleMaps"
      android:versionCode="1"
      android:versionName="1.0.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
 
    <uses-library android:name="com.google.android.maps" />  
 
        <activity android:name=".MapsActivity"
                  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>
 
    <uses-permission android:name="android.permission.INTERNET" />
 
</manifest>
</xml>

Displaying the Map

To display the Google Maps in your Android application, modify the main.xml file located in the res/layout folder. You shall use the <com.google.android.maps.MapView> element to display the Google Maps in your activity. In addition, let's use the <RelativeLayout> element to position the map within the activity:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent">
 
    <com.google.android.maps.MapView 
        android:id="@+id/mapView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:enabled="true"
        android:clickable="true"
        android:apiKey="0l4sCTTyRmXTNo7k8DREHvEaLar2UmHGwnhZVHQ"
        />
 
</RelativeLayout>

Notice from above that I have used the Google Maps key that I obtained earlier and put it into the apiKey attribute.

In the MapsActivity.java file, modify the class to extend from the MapActivity class, instead of the normal Activity class:

package net.learn2develop.GoogleMaps;
 
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import android.os.Bundle;
 
public class MapsActivity extends MapActivity 
{    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
 
    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
}

Observe that if your class extends the MapActivity class, you need to override the isRouteDisplayed() method. You can simply do so by setting the method to return false.

That's it! That's all you need to do to display the Google Maps in your application. Press F11 in Eclipse to deploy the application onto an Android emulator. Figure 3 shows the Google map in all its glory.


Figure 3 Google Maps in your application

At this juncture, take note of a few troubleshooting details. If your program does not run (i.e. it crashes), then it is likely you forgot to put the following statement in your AndroidManifest.xml file:

    <uses-library android:name="com.google.android.maps" />

If your application manages to load but you cannot see the map (all you see is a grid), then it is very likely you do not have a valid Map key, or that you did not specify the INTERNET permission:

    <uses-permission android:name="android.permission.INTERNET" />

Displaying the Zoom View

The previous section showed how you can display the Google Maps in your Android device. You can drag the map to any desired location and it will be updated on the fly. However, observe that there is no way to zoom in or out from a particular location. Thus, in this section, you will learn how you can let users zoom into or out of the map.

First, add a <LinearLayout> element to the main.xml file as shown below:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent">
 
    <com.google.android.maps.MapView 
        android:id="@+id/mapView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:enabled="true"
        android:clickable="true"
        android:apiKey="0l4sCTTyRmXTNo7k8DREHvEaLar2UmHGwnhZVHQ"
        />
 
    <LinearLayout android:id="@+id/zoom" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_alignParentBottom="true" 
        android:layout_centerHorizontal="true" 
        /> 
 
</RelativeLayout>

You will use the <LinearLayout> element to hold the two zoom controls in Google Maps (you will see this shortly).

In the MapsActivity.java file, add the following imports:

import com.google.android.maps.MapView.LayoutParams;  
import android.view.View;
import android.widget.LinearLayout;

and add the following code after the line setContentView(R.layout.main);

        mapView = (MapView) findViewById(R.id.mapView);
        LinearLayout zoomLayout = (LinearLayout)findViewById(R.id.zoom);  
        View zoomView = mapView.getZoomControls(); 
 
        zoomLayout.addView(zoomView, 
            new LinearLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, 
                LayoutParams.WRAP_CONTENT)); 
        mapView.displayZoomControls(true);

The complete MapsActivity.java file is given below:

package net.learn2develop.GoogleMaps;
 
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.MapView.LayoutParams;  
 
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
 
public class MapsActivity extends MapActivity 
{    
    MapView mapView; 
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
 
        mapView = (MapView) findViewById(R.id.mapView);
        LinearLayout zoomLayout = (LinearLayout)findViewById(R.id.zoom);  
        View zoomView = mapView.getZoomControls(); 
 
        zoomLayout.addView(zoomView, 
            new LinearLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, 
                LayoutParams.WRAP_CONTENT)); 
        mapView.displayZoomControls(true);
 
    }
 
    @Override
    protected boolean isRouteDisplayed() {
        // TODO Auto-generated method stub
        return false;
    }
}

Basically, you obtain the MapView instance on the activity, obtain its zoom controls and then add it to the LinearLayout element you added to the activity earlier on. In the above case, the zoom control will be displayed at the bottom of the screen. When you now press F11 in Eclipse, you will see the zoom controls when you touch the map (see Figure 4).


Figure 4 Using the zoom controls in Google Maps

Using the zoom control, you can zoom in or out of a location by simply touching the "+ or "-" buttons on the screen.

Alternatively, you can also programmatically zoom in or out of the map using the zoomIn() and zoomOut() methods from the MapController class:

package net.learn2develop.GoogleMaps;
 
//...
import android.os.Bundle;
import android.view.KeyEvent;
 
public class MapsActivity extends MapActivity 
{    
    MapView mapView; 
 
    public boolean onKeyDown(int keyCode, KeyEvent event) 
    {
        MapController mc = mapView.getController(); 
        switch (keyCode) 
        {
            case KeyEvent.KEYCODE_3:
                mc.zoomIn();
                break;
            case KeyEvent.KEYCODE_1:
                mc.zoomOut();
                break;
        }
        return super.onKeyDown(keyCode, event);
    }    
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        //...
    }
 
    @Override
    protected boolean isRouteDisplayed() {
        // TODO Auto-generated method stub
        return false;
    }
}

In the above code, when the user presses the number 3 on the keyboard the map will zoom in into the next level. Pressing number 1 will zoom out one level.

Changing Views of the Map

By default, the Google Maps displays in the map mode. If you wish to display the map in satellite view, you can use the setSatellite() method of the MapView class, like this:

        mapView.setSatellite(true);

You can also display the map in street view, using the setStreetView() method:

        mapView.setStreetView(true);

Figure 5 shows the Google Maps displayed in satellite and street views, respectively.


Figure 5 Displaying Google Maps in satellite and street views

Displaying a Particular Location

Be default, the Google Maps displays the map of the United States when it is first loaded. However, you can also set the Google Maps to display a particular location. In this case, you can use the animateTo() method of the MapController class.

The following code shows how this is done:

package net.learn2develop.GoogleMaps;
 
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MapView.LayoutParams;
 
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
 
public class MapsActivity extends MapActivity 
{    
    MapView mapView; 
    MapController mc;
    GeoPoint p;
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        mapView = (MapView) findViewById(R.id.mapView);
        LinearLayout zoomLayout = (LinearLayout)findViewById(R.id.zoom);  
        View zoomView = mapView.getZoomControls(); 
 
        zoomLayout.addView(zoomView, 
            new LinearLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, 
                LayoutParams.WRAP_CONTENT)); 
        mapView.displayZoomControls(true);
 
        mc = mapView.getController();
        String coordinates[] = {"1.352566007", "103.78921587"};
        double lat = Double.parseDouble(coordinates[0]);
        double lng = Double.parseDouble(coordinates[1]);
 
        p = new GeoPoint(
            (int) (lat * 1E6), 
            (int) (lng * 1E6));
 
        mc.animateTo(p);
        mc.setZoom(17); 
        mapView.invalidate();
    }
 
    @Override
    protected boolean isRouteDisplayed() {
        // TODO Auto-generated method stub
        return false;
    }
}

In the above code, you first obtain a controller from the MapView instance and assign it to a MapController object (mc). You use a GeoPoint object to represent a geographical location. Note that for this class the latitude and longitude of a location are represented in micro degrees. This means that they are stored as integer values. For a latitude value of 40.747778, you need to multiply it by 1e6 to obtain 40747778.

To navigate the map to a particular location, you can use the animateTo() method of the MapController class (an instance which is obtained from the MapView object). The setZoom() method allows you to specify the zoom level in which the map is displayed. Figure 6 shows the Google Maps displaying the map of Singapore.


Figure 6 Navigating to a particular location on the map

Adding Markers

Very often, you may wish to add markers to the map to indicate places of interests. Let's see how you can do this in Android. First, create a GIF image containing a pushpin (see Figure 7) and copy it into the res/drawable folder of the project. For best effect, you should make the background of the image transparent so that it does not block off parts of the map when the image is added to the map.


Figure 7 Adding an image to the res/drawable folder

To add a marker to the map, you first need to define a class that extends the Overlay class:

package net.learn2develop.GoogleMaps;
 
import java.util.List;
 
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.MapView.LayoutParams;
 
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
 
public class MapsActivity extends MapActivity 
{    
    MapView mapView; 
    MapController mc;
    GeoPoint p;
 
    class MapOverlay extends com.google.android.maps.Overlay
    {
        @Override
        public boolean draw(Canvas canvas, MapView mapView, 
        boolean shadow, long when) 
        {
            super.draw(canvas, mapView, shadow);                   
 
            //---translate the GeoPoint to screen pixels---
            Point screenPts = new Point();
            mapView.getProjection().toPixels(p, screenPts);
 
            //---add the marker---
            Bitmap bmp = BitmapFactory.decodeResource(
                getResources(), R.drawable.pushpin);            
            canvas.drawBitmap(bmp, screenPts.x, screenPts.y-50, null);         
            return true;
        }
    } 
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        //...
    }
 
    @Override
    protected boolean isRouteDisplayed() {
        // TODO Auto-generated method stub
        return false;
    }
}

In the MapOverlay class that you have defined, override the draw() method so that you can draw the pushpin image on the map. In particular, note that you need to translate the geographical location (represented by a GeoPoint object, p) into screen coordinates.

As you want the pointed tip of the push pin to indicate the position of the location, you would need to deduct the height of the image (which is 50 pixels) from the y-coordinate of the point (see Figure 8) and draw the image at that location.


Figure 8 Adding an image to the map

To add the marker, create an instance of the MapOverlap class and add it to the list of overlays available on the MapView object:

    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        //...
 
        mc.animateTo(p);
        mc.setZoom(17); 
 
        //---Add a location marker---
        MapOverlay mapOverlay = new MapOverlay();
        List<Overlay> listOfOverlays = mapView.getOverlays();
        listOfOverlays.clear();
        listOfOverlays.add(mapOverlay);        
 
        mapView.invalidate();
    }

Figure 9 shows how the pushpin looks like when added to the map.


Figure 9 Adding a marker to the map

Getting the Location that was touched

After using Google Maps for a while, you may wish to know the latitude and longitude of a location corresponding to the position on the screen that you have just touched. Knowing this information is very useful as you can find out the address of a location, a process known as Geocoding (you will see how this is done in the next section).

If you have added an overlay to the map, you can override the onTouchEvent() method within the Overlay class. This method is fired every time the user touches the map. This method has two parameters - MotionEvent and MapView. Using the MotionEvent parameter, you can know if the user has lifted his finger from the screen using the getAction() method. In the following code, if the user has touched and then lifted his finger, you will display the latitude and longitude of the location touched:

    class MapOverlay extends com.google.android.maps.Overlay
    {
        @Override
        public boolean draw(Canvas canvas, MapView mapView, 
        boolean shadow, long when) 
        {
           //...
        }
 
        @Override
        public boolean onTouchEvent(MotionEvent event, MapView mapView) 
        {   
            //---when user lifts his finger---
            if (event.getAction() == 1) {                
                GeoPoint p = mapView.getProjection().fromPixels(
                    (int) event.getX(),
                    (int) event.getY());
                    Toast.makeText(getBaseContext(), 
                        p.getLatitudeE6() / 1E6 + "," + 
                        p.getLongitudeE6() /1E6 , 
                        Toast.LENGTH_SHORT).show();
            }                            
            return false;
        }        
    }

Figure 10 shows this in action.


Figure 10 Displaying the latitude and longitude of a point touched on the map

Geocoding and Reverse Geocoding

If you know the latitude and longitude of a location, you can find out its address using a process known as Geocoding. Google Maps in Android supports this via the Geocoder class. The following code shows how you can find out the address of a location you have just touched using the getFromLocation() method:

    class MapOverlay extends com.google.android.maps.Overlay
    {
        @Override
        public boolean draw(Canvas canvas, MapView mapView, 
        boolean shadow, long when) 
        {
          //...
        }
 
        @Override
        public boolean onTouchEvent(MotionEvent event, MapView mapView) 
        {   
            //---when user lifts his finger---
            if (event.getAction() == 1) {                
                GeoPoint p = mapView.getProjection().fromPixels(
                    (int) event.getX(),
                    (int) event.getY());
 
                Geocoder geoCoder = new Geocoder(
                    getBaseContext(), Locale.getDefault());
                try {
                    List<Address> addresses = geoCoder.getFromLocation(
                        p.getLatitudeE6()  / 1E6, 
                        p.getLongitudeE6() / 1E6, 1);
 
                    String add = "";
                    if (addresses.size() > 0) 
                    {
                        for (int i=0; i<addresses.get(0).getMaxAddressLineIndex(); 
                             i++)
                           add += addresses.get(0).getAddressLine(i) + "\n";
                    }
 
                    Toast.makeText(getBaseContext(), add, Toast.LENGTH_SHORT).show();
                }
                catch (IOException e) {                
                    e.printStackTrace();
                }   
                return true;
            }
            else                
                return false;
        }        
    }

Figure 11 shows the above code in action.


Figure 11 Performing Geocoding in Google Maps

If you know the address of a location but want to know its latitude and longitude, you can do so via reverse-Geocoding. Again, you can use the Geocoder class for this purpose. The following code shows how you can find the exact location of the Empire State Building by using the getFromLocationName() method:

        Geocoder geoCoder = new Geocoder(this, Locale.getDefault());    
        try {
            List<Address> addresses = geoCoder.getFromLocationName(
                "empire state building", 5);
            String add = "";
            if (addresses.size() > 0) {
                p = new GeoPoint(
                        (int) (addresses.get(0).getLatitude() * 1E6), 
                        (int) (addresses.get(0).getLongitude() * 1E6));
                mc.animateTo(p);    
                mapView.invalidate();
            }    
        } catch (IOException e) {
            e.printStackTrace();
        }

Once the location is found, the above code navigates the map to the location. Figure 12 shows the code in action.


Figure 12 Navigating to the Empire State Building

Summary

In this article, you have learnt a few tricks for the Google Maps in Android. Using Google Maps, there are many interesting projects you can work on, such as geo-tagging, geo-tracking, etc. If you have cool ideas on building cool location-based services, share with us in the comments box below. Have fun!