'Android'에 해당되는 글 20건
- 2010.12.28 안드로이드 Intent에서 앱 호출하는 방법을 정리 16
- 2010.04.13 Android의 9 patch(나인패치) drawable 이란?
- 2010.04.12 안드로이드 010: TableLayout 컨테이너 / ScrollView (Android Container 3: TableLayout / ScrollView) 2
- 2010.02.02 How to make a simple Android widget 5
- 2010.01.28 Using Google Maps in Android 63
- 2010.01.22 A Visual Guide to Android GUI Widgets
- 2010.01.21 안드로이드 에뮬레이터에 가상의 SD카드 마운트시키기
- 2010.01.20 Web View 샘플구현 8
- 2010.01.18 [Source] SD 카드에 저장되어 있는 비디오 목록 출력및 비디오 실행하기 11
- 2010.01.18 안드로이드 암시적 인텐트(Implicit Intent)를 사용해보자!
안드로이드 Intent에서 앱 호출하는 방법을 정리
연락처 Intent
- 연락처 조회
intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("content://contacts/people/" +
String.valueOf(contact.getId())));
startActivity(intent);
- 연락처 등록
intent = new Intent(Intent.ACTION_INSERT,
Uri.parse("content://contacts/people"));
startActivity(intent);
- 연락처 수정
intent = new Intent(Intent.ACTION_EDIT,
Uri.parse("content://contacts/people/" +
String.valueOf(contact.getId())));
startActivity(intent);
- 연락처 삭제
intent = new Intent(Intent.ACTION_DELETE,
Uri.parse("content://contacts/people/" +
String.valueOf(contact.getId())));
startActivity(intent);
전화 Intent
- 권한 설정 (AndroidManifest.xml)
전화 걸기 : CALL_PHONE = "android.permission.CALL_PHONE"
긴급 통화 : CALL_PRIVILEGED =
"android.permission.CALL_PRIVILEGED"
폰 상태 읽기 : READ_PHONE_STATE =
"android.permission.READ_PHONE_STATE"
폰 상태 수정 : MODIFY_PHONE_STATE =
"android.permission.MODIFY_PHONE_STATE"
브로드케스팅 수신 : PROCESS_OUTGOING_CALLS =
"android.permission.PROCESS_OUTGOING_CALLS"
전화 걸기 이전 : ACTION_NEW_OUTGOING_CALL =
"android.intent.action.NEW_OUTGOING_CALL"
- 전화걸기 화면
Intent intent = new Intent(Intent.ACTION_DIAL,
Uri.parse("tel:" + TelNumber));
startActivity(intent);
- 전화걸기
Intent intent = new Intent(Intent.ACTION_CALL,
Uri.parse("tel:" + TelNumber));
startActivity(intent);
SMS Intent
- 권한 설정 (AndroidManifest.xml)
수신 모니터링 : RECEIVE_SMS = "android.permission.RECEIVE_SMS"
읽기 가능 : READ_SMS = "android.permission.READ_SMS"
발송 가능 : SEND_SMS = "android.permission.SEND_SMS"
SMS Provider로 전송 : WRITE_SMS = "android.permission.WRITE_SMS"
: BROADCAST_SMS = "android.permission.BROADCAST_SMS"
- SMS 발송 화면
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra("sms_body", "The SMS text");
intent.setType("vnd.android-dir/mms-sms");
startActivity(intent);
- SMS 보내기
Intent intent = new Intent(Intent.ACTION_SENDTO,
Uri.parse("smsto://" + contact.getHandphone()));
intent.putExtra("sms_body", "The SMS text");
intent.setType("vnd.android-dir/mms-sms");
startActivity(intent);
이메일 Intent
- 이메일 발송 화면
Intent intent = new Intent(Intent.ACTION_SENDTO,
Uri.parse("mailto:" + contact.getEmail()));
startActivity(intent);
브라우저 Intent
- Browser에서 URL 호출하기
new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com/"));
startActivity(intent);
- 브라우저에서 검색
Intent intent = new Intent(Intent.ACT ION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, "검색어");
startActivity(intent);
지도 Intent
- 지도 보기
Uri uri = Uri.parse ("geo: 38.00, -35.03");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
안드로이드 마켓 Intent
- 안드로이드 마켓에서 Apps 검색
Uri uri = Uri.parse("market://search?q=pname:전제_패키지_명");
//--- 예) market://search?q=pname:com.jopenbusiness.android.smartsearch
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
- 안드로이드 마켓의 App 상세 화면
Uri uri = Uri.parse("market://details?id=전제_패키지_명");
//--- 예) market://details?id=com.jopenbusiness.android.smartsearch
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
갤럭시S의 Intent
- 패키지명과 클래스명으로 App 호출
intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName("패키지명", "전체_클래스명"));
startActivity(intent);
- 전화, SMS
-
- 전화번호부 : com.android.contacts, com.sec.android.app.contacts.PhoneBookTopMenuActivity
- 전화 : com.sec.android.app.dialertab, com.sec.android.app.dialertab.DialerTabActivity
- 최근기록 : com.sec.android.app.dialertab, com.sec.android.app.dialertab.DialerTabDialerActivity
- 메시지 : com.sec.mms, com.sec.mms.Mms
- 이메일 : com.android.email, com.android.email.activity.Welcome
- 일정 : com.android.calendar, com.android.calendar.LaunchActivity
- 인터넷 : com.android.browser, com.android.browser.BrowserActivity
- Google의 Android용 앱
-
- 검색 : com.google.android.googlequicksearchbox, com.google.android.googlequicksearchbox.SearchActivity
- 음성 검색 : com.google.android.voicesearch, com.google.android.voicesearch.RecognitionActivity
- Gmail : com.google.android.gm, com.google.android.gm.ConversationListActivityGmail
- 지도 : com.google.android.apps.maps, com.google.android.maps.MapsActivity
- 위치찾기 : com.google.android.apps.maps, com.google.android.maps.LatitudeActivity
- YouTube : com.google.android.youtube, com.google.android.youtube.HomeActivity
- 토크 : com.google.android.talk, com.google.android.talk.SigningInActivity
- Goggles : com.google.android.apps.unveil, com.google.android.apps.unveil.CaptureActivity
- Google 번역 : com.google.android.apps.translate, com.google.android.apps.translate.HomeActivity
- Reader : com.google.android.apps.reader, com.google.android.apps.unveil.CaptureActivity
- Voice : com.google.android.apps.googlevoice, com.google.android.apps.googlevoice.SplashActivity
- Google 별지도 : com.google.android.stardroid, com.google.android.stardroid.activities.SplashScreenActivity
- 카메라 : com.sec.android.app.camera, com.sec.android.app.camera.Camera
- TV : com.sec.android.app.dmb, com.sec.android.app.dmb.activity.DMBFullScreenView
- Android 관리
-
- 환경 설정 : com.android.settings, com.android.settings.Settings
- 작업 관리자 : com.sec.android.app.controlpanel, com.sec.android.app.controlpanel.activity.JobManagerActivity
- 마켓 : com.android.vending, com.android.vending.AssetBrowserActivity
출처 : http://www.jopenbusiness.com/tc/oss/entry/Android-Intent-%ED%99%9C%EC%9A%A9-%EC%82%AC%EB%A1%80
Android의 9 patch(나인패치) drawable 이란?
일반 PNG 이미지에서 1pixel의 보더를 가지는 형태로 구성되어있습니다. 이 보더가 늘어나는 영역과 늘어나지 않는 영역을 정의하게 됩니다. 왼쪽과 위쪽의 1 pixel 검은색 선은 늘어날 수 있는 부분을 정의합니다. 늘어날 수 있는 부분은 여러개가 될 수 있습니다.
오른쪽과 아래쪽의 1 pixel 검은색 선은 뷰가 그려질 영역을 정하는 일을 합니다. 다시 말해 패딩 영역을 결정합니다. 만약 이 선을 그리지 않는다면 왼쪽과 위쪽의 선이 사용됩니다. 예를 들어 텍스트뷰의 경우 그려질 텍스트가 이 선이 그려진 영역안에서 표시됩니다.
나인패치 이미지를 쉽게 만들기 위해서 SDK의 Tools디렉토리에 draw9patch라고 하는 이미지 에디터가 들어있습니다. 아니면 그냥 일반적인 그래픽 에디터에서 그려도 상관없습니다.
파일이름은 반드시 .9.png라고 끝나도록 저장해주어야 합니다. res/drawable/some_name.9.png 와 같은 형태가 되겠지요. 만약 그냥 png라고 끝난다면 일반 이미지 파일로 처리가 됩니다.
예제를 한번 확인해보시지요. 왼쪽의 버튼과 오른쪽의 버튼은 모두 같은 나인패치 Drawable을 백그라운드 이미지로 사용하고 있습니다. 이미지 파일 하나로 다양한 크기의 버튼의 백그라운드로 사용될 수 있다는 것은 정말 편리하고 UI작업을 할 때 항상 사용하는 것이니 알아두시면 좋습니다.
http://www.androidpub.com/2096
이번에는 위젯들을 화면에 배치 하는데 필요한 container에 관한 내용입니다.
다음과 같이 3부분으로 나누어서 포스팅 하려고 합니다.
Part 3. TableLayout + ScrollView
그중 Part 3. TableLayout에 대한 정리 입니다.
3. TableLayout (Grid Model)
TableLayout 컨테이너는 HTML과 같이 방식으로 쓰인다.
즉, 위젯을 테이블에 배치하고, 테이블의 행과 열의 간격을 조정하여 위젯의 크기를 결정하는 방식이다.
Table 구성하기
TableLayout은 TableRow와 같이 사용된다.
TableLayout은 테이블의 전반적인 사항을 관리하고, TableRow로 테이블에 행을 하나씩 추가하고, 추가한 행에 위젯(들)을 배치하는 한다.
TableLayout 예제 (main.xml) *속성 적용 전
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
02 |
< TableLayout xmlns:android = "http://schemas.android.com/apk/res/android" |
03 |
android:layout_width = "fill_parent" |
04 |
android:layout_height = "fill_parent" > |
05 |
|
06 |
<!-- Row 0 --> |
07 |
< TableRow > |
08 |
< TextView |
09 |
android:id = "@+id/textview1" |
10 |
android:text = "Row0 : Column0" |
11 |
android:textColor = "#000000" |
12 |
android:background = "#FFFFFF" /> |
13 |
< TextView |
14 |
android:id = "@+id/textview2" |
15 |
android:text = "Row0 : Column1" |
16 |
android:textColor = "#000000" |
17 |
android:background = "#FF0000" /> |
18 |
< TextView |
19 |
android:id = "@+id/textview3" |
20 |
android:text = "Row0 : Column2" |
21 |
android:textColor = "#000000" |
22 |
android:background = "#FFFFFF" /> |
23 |
< TextView |
24 |
android:id = "@+id/textview4" |
25 |
android:text = "Row0 : Column3" |
26 |
android:textColor = "#000000" |
27 |
android:background = "#FF0000" /> |
28 |
</ TableRow > |
29 |
|
30 |
<!-- Row 1 --> |
31 |
< TableRow > |
32 |
< TextView |
33 |
android:id = "@+id/textview5" |
34 |
android:text = "Row1 : Column0" |
35 |
android:textColor = "#000000" |
36 |
android:background = "#FFFF00" /> |
37 |
< TextView |
38 |
android:id = "@+id/textview6" |
39 |
android:text = "Row1 : Column1" |
40 |
android:textColor = "#000000" |
41 |
android:background = "#00FF00" /> |
42 |
< TextView |
43 |
android:id = "@+id/textview7" |
44 |
android:text = "Row1 : Column2" |
45 |
android:textColor = "#000000" |
46 |
android:background = "#FFFF00" /> |
47 |
< TextView |
48 |
android:id = "@+id/textview8" |
49 |
android:text = "Row1 : Column4" |
50 |
android:textColor = "#000000" |
51 |
android:layout_column = "4" |
52 |
android:background = "#00FF00" /> |
53 |
</ TableRow > |
54 |
</ TableLayout > |
위의 예제의 경우, 테이블은 2개의 행으로 이루어져 있으며
첫 번째 행과 두 번째 행 모두 4개의 TextView로 이루어져 있다.
위의 XML Layout을 일반적으로 사용하는 테이블로 시각화 시킨다면 다음과 같다.
Row1 : Column4 처럼 위젯을 특정 column에 배치하는 TableRow.LayoutParams 의 속성은 다음과 같다.
또, 테이블의 전체 column 수는 column수가 가장 많은 row에 따른다.
위의 경우 Row0은 순차적으로 4개의 cell을 소모하여 4개의 column이면 충분히 표현 가능하지만,
Row1은 마지막 위젯이 cell 하나를 건너뛰어 배치되어서 총 5개의cell이 사용되었다.
그럼으로 테이블 전체 column수는 row1의 column수에 따라 5 column 테이블이 된다.
다음은 예제를 실행한 화면이다. cell들의 너비가 넓어 테이블이 화면을 벋어났지만 다음에서 해결한다.
셀(Cell)의 너비 줄이기(shrink) *참고: 테이블 좌우 폭이 컨테이너 폭보다 넓은 경우에만 효과 있음.
위 실행 화면에서 보면, 테이블의 전체 너비가 컨테이너 너비보다 넓어 컨테이너 밖으로 삐쳐 나간 것을 볼 수 있다.
경우에 따라서는 테이블의 column(들)의 너비를 인위적으로 줄여 테이블 전체가 보이도록 할 필요가 있다.
column(들)의 너비가 화면에 적당하도록 줄이려면 TableLayout의 다음 속성을 사용한다.
1~n 개의 column에 적용 가능하며 복수의 column은 쉼표 (,) 로 구분하며 전체 column을 줄이려면 아스테리스크(*)를 사용한다.
또, column의 너비가 줄어들면서 위젯이 표현하는 컨텐트(예. string object)의 너비가 위젯의 view 너비 보다 커서 하나의 라인에 정상적으로 표현할 수 없게 되면 자동으로 줄 바꿈이 일어난다.
Java 코드에서는 setColumnShrinkable 또는 setShrinkAllColumns 메소드를 사용.
다음은 예제에 android:shrinkColumns="*"를 적용한 화면. 모든 cell들이 정상적으로 보인 반면 줄 바꿈이 일어났다.
셀(Cell) 숨기기(collapse)
필요에 따라서 테이블의 특정 셀이 존재는 하지만 보이지 않게 숨겨야 할 경우도 있다.
역시 TableLayout의 속성이며 1~n 개의 column에 적용가능 하다. 복수의 column은 쉼표 (,) 로 구분하며 전체 column을 숨기려면 아스테리스크(*)를 사용한다.
자바 코드에서는 setColumnCollapsed 메소드를 사용.
다음은 예제에 android:collapseColumns="0, 1"를 적용한 화면이다. column 0, 1이 보이지 않는 것을 확인할 수 있다.
셀(Cell) 합치기
위젯이 2개이상의 column에 걸쳐 나타나게 할 수 있는데 이를 결정하는 TableRow.LayoutParams 의 속성은 다음과 같다.
예제 중 Row1 : Column 2 에 위치한 EditText 위젯에 android:layout_span="2" 속성을 적용하면 테이블이 다음과 같아진다.
셀(Cell) 늘리기(stretch) *참고: 테이블 좌우 폭이 컨테이너 폭보다 좁을 경우에만 효과 있음.
TableLayout 컨테이너에 배치된 위젯의 넓이는 그 위젯이 속한 컬럼에서 가장 넓은 위젯의 크기를 따른다.
하지만 필요에 따라 특정 위젯이 속한 column의 너비를 인위적으로 늘릴 필요가 있다.
이럴경우 TableLayout의 다음 속성을 사용한다.
속성에 지정된 column외의 column들이 소비하고 남은 모든 여유공간을 지정된 column(들)이 차지하게 된다.
Java 코드에서는 TableLayout의 setColumnStretchable 이나 setStretchAllColumns 메소드를 이용.
예제에서 column4를 늘리면 다음과 같이 테이블 형태가 변한다. 이전 그림과 비교해 보면 Row1 : Column4 가 화면 끝까지 확장 된 것을 볼 수 있다.
TableLayout 중간에 TableRow가 아닌 위젯 삽입하기
TableLayout의 중간에 TableRow가 아닌 위젯이 올 수도 있다.
단, 그런 요소의의 경우 다음과 같은 특징을 갖는다.
- TableLayout은 orientation이 vertical로 지정된LinearLayout 처럼 작동함.
- android:layout_width속성이 무조건 "fill_parent"로 고정됨.
예제의 두 TableRow 사이에 다음과 같은 코드를 삽입 한다면,
TableLayout 내부의 TableRow가 아닌 요소 예제 (main.xml 의 일부)
1 |
< View |
2 |
android:layout_height = "4px" |
3 |
android:background = "#FF00FF" /> |
실행 화면은 다음과 같이 된다. Row 0과 Row 1사이의 핑크색 경계선을 볼 수 있다.
다음은 위 실행화면에 대한 소스코드이다. 지금까지 정리한 여러 속성들이 사용된 것을 확인할 수 있다.
TableLayout 예제 코드 (main.xml) *여러 속성 적용 후
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
02 |
< TableLayout xmlns:android = "http://schemas.android.com/apk/res/android" |
03 |
android:layout_width = "fill_parent" |
04 |
android:layout_height = "fill_parent" |
05 |
android:shrinkColumns = "*" |
06 |
android:collapseColumns = "0, 1" |
07 |
android:stretchColumns = "4" > |
08 |
|
09 |
<!-- Row 0 --> |
10 |
< TableRow > |
11 |
< TextView |
12 |
android:id = "@+id/textview1" |
13 |
android:text = "Row0 : Column0" |
14 |
android:textColor = "#000000" |
15 |
android:background = "#FFFFFF" /> |
16 |
< TextView |
17 |
android:id = "@+id/textview2" |
18 |
android:text = "Row0 : Column1" |
19 |
android:textColor = "#000000" |
20 |
android:background = "#FF0000" /> |
21 |
< TextView |
22 |
android:id = "@+id/textview3" |
23 |
android:text = "Row0 : Column2" |
24 |
android:textColor = "#000000" |
25 |
android:background = "#FFFFFF" /> |
26 |
< TextView |
27 |
android:id = "@+id/textview4" |
28 |
android:text = "Row0 : Column3" |
29 |
android:textColor = "#000000" |
30 |
android:background = "#FF0000" /> |
31 |
</ TableRow > |
32 |
|
33 |
<!-- TableLayout 내부의 TableRow가 아닌 요소 --> |
34 |
< View |
35 |
android:layout_height = "4px" |
36 |
android:background = "#FF00FF" /> |
37 |
|
38 |
<!-- Row 1 --> |
39 |
< TableRow > |
40 |
< TextView |
41 |
android:id = "@+id/textview5" |
42 |
android:text = "Row1 : Column0" |
43 |
android:textColor = "#000000" |
44 |
android:background = "#FFFF00" /> |
45 |
< TextView |
46 |
android:id = "@+id/textview6" |
47 |
android:text = "Row1 : Column1" |
48 |
android:textColor = "#000000" |
49 |
android:background = "#00FF00" /> |
50 |
< TextView |
51 |
android:id = "@+id/textview7" |
52 |
android:text = "Row1 : Column2" |
53 |
android:textColor = "#000000" |
54 |
android:background = "#FFFF00" |
55 |
android:layout_span = "2" /> |
56 |
< TextView |
57 |
android:id = "@+id/textview8" |
58 |
android:text = "Row1 : Column4" |
59 |
android:textColor = "#000000" |
60 |
android:layout_column = "4" |
61 |
android:background = "#00FF00" /> |
62 |
</ TableRow > |
63 |
</ TableLayout > |
4. Container Scroll 하기
스마트폰의 화면은 크기가 제한적 임으로 스크롤의 사용이 중요하다.
스크롤 구현 방법은 다음과 같이 스크롤 시키고 싶은 container를 ScrollView elememt내부에 nest 시키면 된다.
ScrollView 예제 (main.xml)
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
02 |
< ScrollView xmlns:android = "http://schemas.android.com/apk/res/android" |
03 |
android:layout_height = "fill_parent" |
04 |
android:layout_width = "fill_parent" > |
05 |
|
06 |
<!-- 어떤 Layout을 사용해도 상관없음 --> |
07 |
<!-- 스크롤 바를 위한 공간 확보용 paddingRight="5px" 주목 --> |
08 |
< LinearLayout |
09 |
android:orientation = "vertical" |
10 |
android:layout_width = "fill_parent" |
11 |
android:layout_height = "fill_parent" |
12 |
android:paddingRight = "5px" > |
13 |
< TextView |
14 |
android:layout_width = "fill_parent" |
15 |
android:layout_height = "300px" |
16 |
android:background = "#FF0000" |
17 |
android:text = "TextView 1" /> |
18 |
< TextView |
19 |
android:layout_width = "fill_parent" |
20 |
android:layout_height = "300px" |
21 |
android:background = "#00FF00" |
22 |
android:text = "TextView 2" /> |
23 |
< TextView |
24 |
android:layout_width = "fill_parent" |
25 |
android:layout_height = "300px" |
26 |
android:background = "#0000FF" |
27 |
android:text = "TextView 3" /> |
28 |
</ LinearLayout > |
29 |
</ ScrollView > |
다음은 실행 화면이다.
완전한 TableLayout API Reference는 다음을 참조.
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
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:
2. Create the Java class
Right-click com.kasperholtze.watchwidget (or whatever you used for package name), and select New -> 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:
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:
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:
<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:
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…
<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.
<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
Using Google Maps in Android
Creating the Project
Using Eclipse, create a new Android project and name GoogleMaps as shown in Figure 1.
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
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!
A Visual Guide to Android GUI Widgets
For rapid development of your user interfaces try DroidDraw
|