Merge commit 'remotes/korg/cupcake' into cupcake_to_master

This commit is contained in:
Jean-Baptiste Queru
2009-03-18 16:57:28 -07:00
302 changed files with 19954 additions and 7180 deletions

View File

@@ -0,0 +1,11 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := user
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := CustomLocale
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0" package="com.android.customlocale">
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
<activity
android:label="@string/app_name" android:name="CustomLocaleActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="NewLocaleDialog"
android:theme="@android:style/Theme.Dialog" />
</application>
<uses-sdk android:minSdkVersion="3" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dip">
<TextView
android:id="@+id/locale_code"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearanceLarge"
android:layout_weight="1"
android:text="@string/locale_default" />
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/locale_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearance"
android:layout_weight="1" />
</LinearLayout>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<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:layout_weight="0"
android:text="@string/header_current_locale"
android:textAppearance="@style/TextAppearance.header"
android:gravity="center_horizontal"
android:background="@color/header_background" />
<TextView
android:id="@+id/current_locale"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:padding="5dip" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:text="@string/header_locale_list"
android:textAppearance="@style/TextAppearance.header"
android:gravity="center_horizontal"
android:background="@color/header_background" />
<ListView
android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:padding="8dip" />
<TextView
android:id="@id/android:empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="@string/no_data_label" />
<Button
android:id="@+id/new_locale"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:paddingLeft="8dip"
android:paddingRight="8dip"
android:text="@string/add_new_locale_button" />
</LinearLayout>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="8dip"
android:paddingRight="8dip">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/new_locale_label" />
<EditText
android:id="@+id/value"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/locale_default" android:inputType="text"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/add"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/add_button" android:layout_gravity="center_vertical"/>
<Button
android:id="@+id/add_and_select"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/add_select_button" android:layout_gravity="center_vertical"/>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<resources>
<string name="app_name">Locales Personalisées</string>
<string name="add_new_locale_button">Ajouter une nouvelle locale</string>
<string name="new_locale_label">Code de la nouvelle locale:</string>
<string name="add_button">Ajouter</string>
<string name="no_data_label">Aucune locale</string>
<string name="header_current_locale">Locale courrante</string>
<string name="header_locale_list">Liste des locales</string>
<string name="add_select_button">Ajouter et sélectionner</string>
</resources>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<resources>
<color name="header_background">#888</color>
</resources>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<resources>
<string name="app_name">Custom Locale</string>
<string name="locale_default">ex_EX</string>
<string name="add_new_locale_button">Add New Locale</string>
<string name="new_locale_label">New locale code:</string>
<string name="add_button">Add</string>
<string name="no_data_label">No data</string>
<string name="header_current_locale">Current Locale</string>
<string name="header_locale_list">Locale List</string>
<string name="add_select_button">Add and Select</string>
</resources>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<resources>
<style name="TextAppearance"
parent="android:TextAppearance" />
<style name="TextAppearance.header">
<item name="android:textSize">14sp</item>
<item name="android:textStyle">bold</item>
</style>
</resources>

View File

@@ -0,0 +1,326 @@
/*
* 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.android.customlocale;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ListActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* Displays the list of system locales as well as maintain a custom list of user
* locales. The user can select a locale and apply it or it can create or remove
* a custom locale.
*/
public class CustomLocaleActivity extends ListActivity {
private static final String CUSTOM_LOCALES_SEP = " ";
private static final String CUSTOM_LOCALES = "custom_locales";
private static final String KEY_CUSTOM = "custom";
private static final String KEY_NAME = "name";
private static final String KEY_CODE = "code";
private static final String TAG = "LocaleSetup";
private static final boolean DEBUG = true;
/** Request code returned when the NewLocaleDialog activity finishes. */
private static final int UPDATE_LIST = 42;
/** Menu item id for applying a locale */
private static final int MENU_APPLY = 43;
/** Menu item id for removing a custom locale */
private static final int MENU_REMOVE = 44;
/** List view displaying system and custom locales. */
private ListView mListView;
/** Textview used to display current locale */
private TextView mCurrentLocaleTextView;
/** Private shared preferences of this activity. */
private SharedPreferences mPrefs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mPrefs = getPreferences(MODE_PRIVATE);
Button newLocaleButton = (Button) findViewById(R.id.new_locale);
newLocaleButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent(CustomLocaleActivity.this, NewLocaleDialog.class);
startActivityForResult(i, UPDATE_LIST);
}
});
mListView = (ListView) findViewById(android.R.id.list);
mListView.setFocusable(true);
mListView.setFocusableInTouchMode(true);
mListView.requestFocus();
registerForContextMenu(mListView);
setupLocaleList();
mCurrentLocaleTextView = (TextView) findViewById(R.id.current_locale);
displayCurrentLocale();
}
@SuppressWarnings("unchecked")
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == UPDATE_LIST && resultCode == RESULT_OK && data != null) {
String locale = data.getExtras().getString(NewLocaleDialog.INTENT_EXTRA_LOCALE);
if (locale != null && locale.length() > 0) {
// Get current custom locale list
String customLocales = mPrefs.getString(CUSTOM_LOCALES, null);
// Update
if (customLocales == null) {
customLocales = locale;
} else {
customLocales += CUSTOM_LOCALES_SEP + locale;
}
// Save prefs
if (DEBUG) {
Log.d(TAG, "add/customLocales: " + customLocales);
}
mPrefs.edit().putString(CUSTOM_LOCALES, customLocales).commit();
Toast.makeText(this, "Added custom locale: " + locale, Toast.LENGTH_SHORT).show();
// Update list view
setupLocaleList();
// Find the item to select it in the list view
ListAdapter a = mListView.getAdapter();
for (int i = 0; i < a.getCount(); i++) {
Object o = a.getItem(i);
if (o instanceof Map<?, ?>) {
String code = ((Map<String, String>) o).get(KEY_CODE);
if (code != null && code.equals(locale)) {
mListView.setSelection(i);
break;
}
}
}
if (data.getExtras().getBoolean(NewLocaleDialog.INTENT_EXTRA_SELECT)) {
selectLocale(locale);
}
}
}
}
private void setupLocaleList() {
if (DEBUG) {
Log.d(TAG, "Update locate list");
}
ArrayList<Map<String, String>> data = new ArrayList<Map<String, String>>();
// Insert all system locales
String[] locales = getAssets().getLocales();
for (String locale : locales) {
Locale loc = new Locale(locale);
Map<String, String> map = new HashMap<String, String>(1);
map.put(KEY_CODE, locale);
map.put(KEY_NAME, loc.getDisplayName());
data.add(map);
}
locales = null;
// Insert all custom locales
String customLocales = mPrefs.getString(CUSTOM_LOCALES, "");
if (DEBUG) {
Log.d(TAG, "customLocales: " + customLocales);
}
for (String locale : customLocales.split(CUSTOM_LOCALES_SEP)) {
if (locale != null && locale.length() > 0) {
Locale loc = new Locale(locale);
Map<String, String> map = new HashMap<String, String>(1);
map.put(KEY_CODE, locale);
map.put(KEY_NAME, loc.getDisplayName() + " [Custom]");
// the presence of the "custom" key marks it as custom.
map.put(KEY_CUSTOM, "");
data.add(map);
}
}
// Sort all locales by code
Collections.sort(data, new Comparator<Map<String, String>>() {
public int compare(Map<String, String> lhs, Map<String, String> rhs) {
return lhs.get(KEY_CODE).compareTo(rhs.get(KEY_CODE));
}
});
// Update the list view adapter
mListView.setAdapter(new SimpleAdapter(this, data, R.layout.list_item, new String[] {
KEY_CODE, KEY_NAME}, new int[] {R.id.locale_code, R.id.locale_name}));
}
@SuppressWarnings("unchecked")
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if (menuInfo instanceof AdapterContextMenuInfo) {
int position = ((AdapterContextMenuInfo) menuInfo).position;
Object o = mListView.getItemAtPosition(position);
if (o instanceof Map<?, ?>) {
String locale = ((Map<String, String>) o).get(KEY_CODE);
String custom = ((Map<String, String>) o).get(KEY_CUSTOM);
if (custom == null) {
menu.setHeaderTitle("System Locale");
menu.add(0, MENU_APPLY, 0, "Apply");
} else {
menu.setHeaderTitle("Custom Locale");
menu.add(0, MENU_APPLY, 0, "Apply");
menu.add(0, MENU_REMOVE, 0, "Remove");
}
}
}
}
@SuppressWarnings("unchecked")
@Override
public boolean onContextItemSelected(MenuItem item) {
String pendingLocale = null;
boolean is_custom = false;
ContextMenuInfo menuInfo = item.getMenuInfo();
if (menuInfo instanceof AdapterContextMenuInfo) {
int position = ((AdapterContextMenuInfo) menuInfo).position;
Object o = mListView.getItemAtPosition(position);
if (o instanceof Map<?, ?>) {
pendingLocale = ((Map<String, String>) o).get(KEY_CODE);
is_custom = ((Map<String, String>) o).get(KEY_CUSTOM) != null;
}
}
if (pendingLocale == null) {
// should never happen
return super.onContextItemSelected(item);
}
if (item.getItemId() == MENU_REMOVE) {
// Get current custom locale list
String customLocales = mPrefs.getString(CUSTOM_LOCALES, "");
if (DEBUG) {
Log.d(TAG, "Remove " + pendingLocale + " from custom locales: " + customLocales);
}
// Update
StringBuilder sb = new StringBuilder();
for (String locale : customLocales.split(CUSTOM_LOCALES_SEP)) {
if (locale != null && locale.length() > 0 && !locale.equals(pendingLocale)) {
if (sb.length() > 0) {
sb.append(CUSTOM_LOCALES_SEP);
}
sb.append(locale);
}
}
String newLocales = sb.toString();
if (!newLocales.equals(customLocales)) {
// Save prefs
mPrefs.edit().putString(CUSTOM_LOCALES, customLocales).commit();
Toast.makeText(this, "Removed custom locale: " + pendingLocale, Toast.LENGTH_SHORT)
.show();
}
} else if (item.getItemId() == MENU_APPLY) {
selectLocale(pendingLocale);
}
return super.onContextItemSelected(item);
}
private void selectLocale(String locale) {
if (DEBUG) {
Log.d(TAG, "Select locale " + locale);
}
try {
IActivityManager am = ActivityManagerNative.getDefault();
Configuration config = am.getConfiguration();
Locale loc = new Locale(locale);
config.locale = loc;
// indicate this isn't some passing default - the user wants this
// remembered
config.userSetLocale = true;
am.updateConfiguration(config);
Toast.makeText(this, "Select locale: " + locale, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
if (DEBUG) {
Log.e(TAG, "Select locale failed", e);
}
}
}
private void displayCurrentLocale() {
try {
IActivityManager am = ActivityManagerNative.getDefault();
Configuration config = am.getConfiguration();
if (config.locale != null) {
String text = String.format("%s - %s",
config.locale.toString(),
config.locale.getDisplayName());
mCurrentLocaleTextView.setText(text);
}
} catch (RemoteException e) {
if (DEBUG) {
Log.e(TAG, "get current locale failed", e);
}
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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.android.customlocale;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
/**
* Dialog to ask the user for a new locale. <p/> Returns the locale code (e.g.
* "en_US") via an intent with a "locale" extra string and a "select" extra
* boolean.
*/
public class NewLocaleDialog extends Activity
implements View.OnClickListener, View.OnKeyListener {
public static final String INTENT_EXTRA_LOCALE = "locale";
public static final String INTENT_EXTRA_SELECT = "select";
private static final String TAG = "NewLocale";
private static final boolean DEBUG = true;
private Button mButtonAdd;
private Button mButtonAddSelect;
private EditText mEditText;
private boolean mWasEmpty;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.new_locale);
mEditText = (EditText) findViewById(R.id.value);
mWasEmpty = true;
mButtonAdd = (Button) findViewById(R.id.add);
mButtonAdd.setOnClickListener(this);
mButtonAdd.setEnabled(false);
mButtonAddSelect = (Button) findViewById(R.id.add_and_select);
mButtonAddSelect.setOnClickListener(this);
mButtonAddSelect.setEnabled(false);
mEditText.setOnKeyListener(this);
}
public void onClick(View v) {
String locale = mEditText.getText().toString();
boolean select = v == mButtonAddSelect;
if (DEBUG) {
Log.d(TAG, "New Locale: " + locale + (select ? " + select" : ""));
}
Intent data = new Intent(NewLocaleDialog.this, NewLocaleDialog.class);
data.putExtra(INTENT_EXTRA_LOCALE, locale);
data.putExtra(INTENT_EXTRA_SELECT, select);
setResult(RESULT_OK, data);
finish();
}
public boolean onKey(View v, int keyCode, KeyEvent event) {
boolean isEmpty = TextUtils.isEmpty(mEditText.getText());
if (isEmpty != mWasEmpty) {
mWasEmpty = isEmpty;
mButtonAdd.setEnabled(!isEmpty);
mButtonAddSelect.setEnabled(!isEmpty);
}
return false;
}
}

View File

@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := eng development tests LOCAL_MODULE_TAGS := eng
LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_STATIC_JAVA_LIBRARIES := googlelogin-client LOCAL_STATIC_JAVA_LIBRARIES := googlelogin-client

View File

@@ -51,12 +51,6 @@
<category android:name="android.intent.category.TEST" /> <category android:name="android.intent.category.TEST" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="PreferredPackages" android:label="Preferred Packages">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.TEST" />
</intent-filter>
</activity>
<activity android:name="ExceptionBrowser" android:label="Exception Browser"> <activity android:name="ExceptionBrowser" android:label="Exception Browser">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@@ -40,6 +40,11 @@ public class PointerLocation extends Activity {
protected void onCreate(Bundle icicle) { protected void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
setContentView(new MyView(this)); setContentView(new MyView(this));
// Make the screen full bright for this activity.
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.screenBrightness = 1.0f;
getWindow().setAttributes(lp);
} }
public class MyView extends View { public class MyView extends View {

View File

@@ -1,189 +0,0 @@
/*
* 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 com.android.development;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.pm.PackageInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class PreferredPackages extends ListActivity {
private static final int ADD_APP_REQUEST = 1;
private PackageListAdapter mAdapter;
private Handler mHandler;
final static class Entry {
final PackageInfo info;
final CharSequence label;
Entry(PackageInfo _info, CharSequence _label) {
info = _info;
label = _label;
}
}
private final ArrayList<Entry> mPackageInfoList = new ArrayList<Entry>();
final class PackageListAdapter extends ArrayAdapter<Entry> {
public PackageListAdapter(Context context) {
super(context, android.R.layout.simple_list_item_1);
List<PackageInfo> pkgs =
context.getPackageManager().getPreferredPackages(0);
final int N = pkgs.size();
mPackageInfoList.clear();
for (int i=0; i<N; i++) {
PackageInfo pi = pkgs.get(i);
if (pi.applicationInfo == null) {
continue;
}
mPackageInfoList.add(new Entry(pi,
getPackageManager().getApplicationLabel(
pi.applicationInfo)));
}
Collections.sort(mPackageInfoList, sDisplayNameComparator);
setSource(mPackageInfoList);
}
public void bindView(View view, Entry info) {
TextView text = (TextView)view.findViewById(android.R.id.text1);
text.setText(info.label);
}
}
private final static Comparator<Entry> sDisplayNameComparator = new Comparator<Entry>() {
public final int
compare(Entry a, Entry b) {
return collator.compare(a.toString(), b.toString());
}
private final Collator collator = Collator.getInstance();
};
/**
* Receives notifications when applications are added/removed.
*/
private final BroadcastReceiver mAppsReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
setupAdapter();
}
};
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setupAdapter();
mHandler = new Handler();
registerIntentReceivers();
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterIntentReceivers();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, 0, 0, "Add Package").setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
addPackage();
return true;
}
});
menu.add(0, 0, 0, "Remove Package").setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
removePackage();
return true;
}
});
return true;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == ADD_APP_REQUEST && resultCode == RESULT_OK) {
getPackageManager().addPackageToPreferred(intent.getAction());
setupAdapter();
}
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Entry info =
mAdapter.itemForPosition(position);
if (info != null) {
Intent intent = new Intent(
Intent.ACTION_VIEW,
Uri.fromParts("package", info.info.packageName, null));
intent.setClass(this, PackageSummary.class);
startActivity(intent);
}
}
private void setupAdapter() {
mAdapter = new PackageListAdapter(this);
setListAdapter(mAdapter);
}
private void removePackage() {
final int curSelection = this.getSelectedItemPosition();
if (curSelection >= 0) {
final Entry packageInfo = mAdapter.itemForPosition(curSelection);
if (packageInfo != null) {
getPackageManager().removePackageFromPreferred(
packageInfo.info.packageName);
}
setupAdapter();
}
}
private void addPackage() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClass(this, AppPicker.class);
startActivityForResult(intent, ADD_APP_REQUEST);
}
private void registerIntentReceivers() {
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
registerReceiver(mAppsReceiver, filter);
}
private void unregisterIntentReceivers() {
unregisterReceiver(mAppsReceiver);
}
}

View File

@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := user development LOCAL_MODULE_TAGS := user
LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_SRC_FILES := $(call all-subdir-java-files)

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="appTitle">Fallback</string>
<string name="error">That action is not currently supported.</string>
<string name="title">Unsupported action</string>
</resources>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="appTitle">"Fallback"</string>
<string name="title">"지원되지 않는 작업"</string>
<string name="error">"이 작업은 현재 지원되지 않습니다."</string>
</resources>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="appTitle">"Fallback"</string>
<string name="title">"Ustøttet handling"</string>
<string name="error">"Denne handlingen er ikke støttet nå."</string>
</resources>

View File

@@ -1,8 +1,6 @@
LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := foo
LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := SdkSetup LOCAL_PACKAGE_NAME := SdkSetup

View File

@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := eng development LOCAL_MODULE_TAGS := eng
LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_SRC_FILES := $(call all-subdir-java-files)

View File

@@ -20,6 +20,17 @@
<resources> <resources>
<string name="app_label">Spare Parts</string> <string name="app_label">Spare Parts</string>
<string name="device_info_title">Device info</string>
<string name="title_battery_history">Battery history</string>
<string name="summary_battery_history">Summary of how battery has been used</string>
<string name="title_battery_information">Battery information</string>
<string name="summary_battery_information">Current battery status information</string>
<string name="title_usage_statistics">Usage statistics</string>
<string name="summary_usage_statistics">Summary of application usage</string>
<string name="general_title">General</string> <string name="general_title">General</string>
<string name="title_window_animations">Window animations</string> <string name="title_window_animations">Window animations</string>
@@ -30,6 +41,14 @@
<string name="summary_transition_animations">Speed of animations moving between screens</string> <string name="summary_transition_animations">Speed of animations moving between screens</string>
<string name="dialog_title_transition_animations">Select transition speed</string> <string name="dialog_title_transition_animations">Select transition speed</string>
<string name="title_fancy_ime_animations">Fancy input animations</string>
<string name="summary_on_fancy_ime_animations">Use fancier animations for input method windows</string>
<string name="summary_off_fancy_ime_animations">Use normal animations for input method windows</string>
<string name="title_haptic_feedback">Haptic feedback</string>
<string name="summary_on_haptic_feedback">Use haptic feedback with user interaction</string>
<string name="summary_off_haptic_feedback">Use haptic feedback with user interaction</string>
<string name="title_font_size">Font size</string> <string name="title_font_size">Font size</string>
<string name="summary_font_size">Overall size of fonts</string> <string name="summary_font_size">Overall size of fonts</string>
<string name="dialog_title_font_size">Select font size</string> <string name="dialog_title_font_size">Select font size</string>
@@ -38,10 +57,6 @@
<string name="summary_end_button">Select End (red) button action</string> <string name="summary_end_button">Select End (red) button action</string>
<string name="dialog_title_end_button">Select End button</string> <string name="dialog_title_end_button">Select End button</string>
<string name="title_accelerometer">Display rotation</string>
<string name="summary_on_accelerometer">Display rotates from orientation</string>
<string name="summary_off_accelerometer">Display rotates when lid is open</string>
<string name="applications_title">Applications</string> <string name="applications_title">Applications</string>
<string name="title_maps_compass">Show compass in Maps</string> <string name="title_maps_compass">Show compass in Maps</string>

View File

@@ -18,6 +18,35 @@
--> -->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/device_info_title">
<PreferenceScreen android:key="battery_history_settings"
android:title="@string/title_battery_history"
android:summary="@string/summary_battery_history">
<intent android:action="android.intent.action.MAIN"
android:targetPackage="com.android.settings"
android:targetClass="com.android.settings.battery_history.BatteryHistory" />
</PreferenceScreen>
<PreferenceScreen android:key="battery_information_settings"
android:title="@string/title_battery_information"
android:summary="@string/summary_battery_information">
<intent android:action="android.intent.action.MAIN"
android:targetPackage="com.android.settings"
android:targetClass="com.android.settings.BatteryInfo" />
</PreferenceScreen>
<PreferenceScreen android:key="usage_statistics_settings"
android:title="@string/title_usage_statistics"
android:summary="@string/summary_usage_statistics">
<intent android:action="android.intent.action.MAIN"
android:targetPackage="com.android.settings"
android:targetClass="com.android.settings.UsageStats" />
</PreferenceScreen>
</PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="@string/general_title"> android:title="@string/general_title">
@@ -37,6 +66,12 @@
android:entryValues="@array/entryvalues_animations" android:entryValues="@array/entryvalues_animations"
android:dialogTitle="@string/dialog_title_transition_animations" /> android:dialogTitle="@string/dialog_title_transition_animations" />
<CheckBoxPreference
android:key="fancy_ime_animations"
android:title="@string/title_fancy_ime_animations"
android:summaryOn="@string/summary_on_fancy_ime_animations"
android:summaryOff="@string/summary_off_fancy_ime_animations"/>
<ListPreference <ListPreference
android:key="font_size" android:key="font_size"
android:title="@string/title_font_size" android:title="@string/title_font_size"
@@ -54,10 +89,10 @@
android:dialogTitle="@string/dialog_title_end_button" /> android:dialogTitle="@string/dialog_title_end_button" />
<CheckBoxPreference <CheckBoxPreference
android:key="accelerometer" android:key="haptic_feedback"
android:title="@string/title_accelerometer" android:title="@string/title_haptic_feedback"
android:summaryOn="@string/summary_on_accelerometer" android:summaryOn="@string/summary_on_haptic_feedback"
android:summaryOff="@string/summary_off_accelerometer"/> android:summaryOff="@string/summary_off_haptic_feedback"/>
</PreferenceCategory> </PreferenceCategory>

View File

@@ -19,7 +19,11 @@ package com.android.spare_parts;
import android.app.ActivityManagerNative; import android.app.ActivityManagerNative;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.RemoteException; import android.os.RemoteException;
@@ -28,6 +32,7 @@ import android.preference.CheckBoxPreference;
import android.preference.ListPreference; import android.preference.ListPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.provider.Settings; import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException; import android.provider.Settings.SettingNotFoundException;
@@ -35,29 +40,72 @@ import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.IWindowManager; import android.view.IWindowManager;
import java.util.List;
public class SpareParts extends PreferenceActivity public class SpareParts extends PreferenceActivity
implements Preference.OnPreferenceChangeListener, implements Preference.OnPreferenceChangeListener,
SharedPreferences.OnSharedPreferenceChangeListener { SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = "SpareParts"; private static final String TAG = "SpareParts";
private static final String BATTERY_HISTORY_PREF = "battery_history_settings";
private static final String BATTERY_INFORMATION_PREF = "battery_information_settings";
private static final String USAGE_STATISTICS_PREF = "usage_statistics_settings";
private static final String WINDOW_ANIMATIONS_PREF = "window_animations"; private static final String WINDOW_ANIMATIONS_PREF = "window_animations";
private static final String TRANSITION_ANIMATIONS_PREF = "transition_animations"; private static final String TRANSITION_ANIMATIONS_PREF = "transition_animations";
private static final String FANCY_IME_ANIMATIONS_PREF = "fancy_ime_animations";
private static final String HAPTIC_FEEDBACK_PREF = "haptic_feedback";
private static final String FONT_SIZE_PREF = "font_size"; private static final String FONT_SIZE_PREF = "font_size";
private static final String END_BUTTON_PREF = "end_button"; private static final String END_BUTTON_PREF = "end_button";
private static final String ACCELEROMETER_PREF = "accelerometer";
private static final String MAPS_COMPASS_PREF = "maps_compass"; private static final String MAPS_COMPASS_PREF = "maps_compass";
private final Configuration mCurConfig = new Configuration(); private final Configuration mCurConfig = new Configuration();
private ListPreference mWindowAnimationsPref; private ListPreference mWindowAnimationsPref;
private ListPreference mTransitionAnimationsPref; private ListPreference mTransitionAnimationsPref;
private CheckBoxPreference mFancyImeAnimationsPref;
private CheckBoxPreference mHapticFeedbackPref;
private ListPreference mFontSizePref; private ListPreference mFontSizePref;
private ListPreference mEndButtonPref; private ListPreference mEndButtonPref;
private CheckBoxPreference mAccelerometerPref;
private CheckBoxPreference mShowMapsCompassPref; private CheckBoxPreference mShowMapsCompassPref;
private IWindowManager mWindowManager; private IWindowManager mWindowManager;
public static boolean updatePreferenceToSpecificActivityOrRemove(Context context,
PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) {
Preference preference = parentPreferenceGroup.findPreference(preferenceKey);
if (preference == null) {
return false;
}
Intent intent = preference.getIntent();
if (intent != null) {
// Find the activity that is in the system image
PackageManager pm = context.getPackageManager();
List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
int listSize = list.size();
for (int i = 0; i < listSize; i++) {
ResolveInfo resolveInfo = list.get(i);
if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
!= 0) {
// Replace the intent with this specific activity
preference.setIntent(new Intent().setClassName(
resolveInfo.activityInfo.packageName,
resolveInfo.activityInfo.name));
return true;
}
}
}
// Did not find a matching activity, so remove the preference
parentPreferenceGroup.removePreference(preference);
return true;
}
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
@@ -69,23 +117,35 @@ public class SpareParts extends PreferenceActivity
mWindowAnimationsPref.setOnPreferenceChangeListener(this); mWindowAnimationsPref.setOnPreferenceChangeListener(this);
mTransitionAnimationsPref = (ListPreference) prefSet.findPreference(TRANSITION_ANIMATIONS_PREF); mTransitionAnimationsPref = (ListPreference) prefSet.findPreference(TRANSITION_ANIMATIONS_PREF);
mTransitionAnimationsPref.setOnPreferenceChangeListener(this); mTransitionAnimationsPref.setOnPreferenceChangeListener(this);
mFancyImeAnimationsPref = (CheckBoxPreference) prefSet.findPreference(FANCY_IME_ANIMATIONS_PREF);
mHapticFeedbackPref = (CheckBoxPreference) prefSet.findPreference(HAPTIC_FEEDBACK_PREF);
mFontSizePref = (ListPreference) prefSet.findPreference(FONT_SIZE_PREF); mFontSizePref = (ListPreference) prefSet.findPreference(FONT_SIZE_PREF);
mFontSizePref.setOnPreferenceChangeListener(this); mFontSizePref.setOnPreferenceChangeListener(this);
mEndButtonPref = (ListPreference) prefSet.findPreference(END_BUTTON_PREF); mEndButtonPref = (ListPreference) prefSet.findPreference(END_BUTTON_PREF);
mEndButtonPref.setOnPreferenceChangeListener(this); mEndButtonPref.setOnPreferenceChangeListener(this);
mAccelerometerPref = (CheckBoxPreference) prefSet.findPreference(ACCELEROMETER_PREF);
mShowMapsCompassPref = (CheckBoxPreference) prefSet.findPreference(MAPS_COMPASS_PREF); mShowMapsCompassPref = (CheckBoxPreference) prefSet.findPreference(MAPS_COMPASS_PREF);
mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); final PreferenceGroup parentPreference = getPreferenceScreen();
updatePreferenceToSpecificActivityOrRemove(this, parentPreference,
BATTERY_HISTORY_PREF, 0);
updatePreferenceToSpecificActivityOrRemove(this, parentPreference,
BATTERY_INFORMATION_PREF, 0);
updatePreferenceToSpecificActivityOrRemove(this, parentPreference,
USAGE_STATISTICS_PREF, 0);
parentPreference.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
} }
private void updateToggles() { private void updateToggles() {
try { try {
mAccelerometerPref.setChecked(Settings.System.getInt( mFancyImeAnimationsPref.setChecked(Settings.System.getInt(
getContentResolver(), getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION, 0) != 0); Settings.System.FANCY_IME_ANIMATIONS, 0) != 0);
mHapticFeedbackPref.setChecked(Settings.System.getInt(
getContentResolver(),
Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) != 0);
Context c = createPackageContext("com.google.android.apps.maps", 0); Context c = createPackageContext("com.google.android.apps.maps", 0);
mShowMapsCompassPref.setChecked(c.getSharedPreferences("extra-features", MODE_WORLD_READABLE) mShowMapsCompassPref.setChecked(c.getSharedPreferences("extra-features", MODE_WORLD_READABLE)
.getBoolean("compass", false)); .getBoolean("compass", false));
@@ -177,10 +237,14 @@ public class SpareParts extends PreferenceActivity
} }
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (ACCELEROMETER_PREF.equals(key)) { if (FANCY_IME_ANIMATIONS_PREF.equals(key)) {
Settings.System.putInt(getContentResolver(), Settings.System.putInt(getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION, Settings.System.FANCY_IME_ANIMATIONS,
mAccelerometerPref.isChecked() ? 1 : 0); mFancyImeAnimationsPref.isChecked() ? 1 : 0);
} else if (HAPTIC_FEEDBACK_PREF.equals(key)) {
Settings.System.putInt(getContentResolver(),
Settings.System.HAPTIC_FEEDBACK_ENABLED,
mHapticFeedbackPref.isChecked() ? 1 : 0);
} else if (MAPS_COMPASS_PREF.equals(key)) { } else if (MAPS_COMPASS_PREF.equals(key)) {
try { try {
Context c = createPackageContext("com.google.android.apps.maps", 0); Context c = createPackageContext("com.google.android.apps.maps", 0);

View File

@@ -4,7 +4,8 @@
<activity android:name="Term" <activity android:name="Term"
android:theme="@style/Theme" android:theme="@style/Theme"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:configChanges="keyboard|keyboardHidden|orientation"> android:configChanges="keyboard|keyboardHidden|orientation"
android:windowSoftInputMode="adjustResize|stateVisible">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.TEST" /> <category android:name="android.intent.category.TEST" />

View File

@@ -48,6 +48,13 @@ import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.FileInputStream; import java.io.FileInputStream;
@@ -177,6 +184,9 @@ public class Term extends Activity {
mKeyListener = new TermKeyListener(); mKeyListener = new TermKeyListener();
mEmulatorView.setFocusable(true);
mEmulatorView.requestFocus();
updatePrefs(); updatePrefs();
} }
@@ -2583,7 +2593,6 @@ class EmulatorView extends View implements GestureDetector.OnGestureListener {
private FileOutputStream mTermOut; private FileOutputStream mTermOut;
private ByteQueue mByteQueue; private ByteQueue mByteQueue;
private final static int MAX_BYTES_PER_UPDATE = 4 * 1024;
/** /**
* Used to temporarily hold data received from the remote process. Allocated * Used to temporarily hold data received from the remote process. Allocated
@@ -2643,6 +2652,117 @@ class EmulatorView extends View implements GestureDetector.OnGestureListener {
invalidate(); invalidate();
} }
@Override
public boolean onCheckIsTextEditor() {
return true;
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
return new BaseInputConnection(this, false) {
public boolean beginBatchEdit() {
return true;
}
public boolean clearMetaKeyStates(int states) {
return true;
}
public boolean commitCompletion(CompletionInfo text) {
return true;
}
public boolean commitText(CharSequence text, int newCursorPosition) {
sendText(text);
return true;
}
public boolean deleteSurroundingText(int leftLength, int rightLength) {
return true;
}
public boolean endBatchEdit() {
return true;
}
public boolean finishComposingText() {
return true;
}
public int getCursorCapsMode(int reqModes) {
return 0;
}
public ExtractedText getExtractedText(ExtractedTextRequest request,
int flags) {
return null;
}
public CharSequence getTextAfterCursor(int n, int flags) {
return null;
}
public CharSequence getTextBeforeCursor(int n, int flags) {
return null;
}
public boolean hideStatusIcon() {
return true;
}
public boolean performContextMenuAction(int id) {
return true;
}
public boolean performPrivateCommand(String action, Bundle data) {
return true;
}
public boolean sendKeyEvent(KeyEvent event) {
switch(event.getKeyCode()) {
case KeyEvent.KEYCODE_ENTER:
sendChar('\r');
break;
case KeyEvent.KEYCODE_DEL:
sendChar(127);
break;
}
return true;
}
public boolean setComposingText(CharSequence text, int newCursorPosition) {
return true;
}
public boolean setSelection(int start, int end) {
return true;
}
public boolean showStatusIcon(String packageName, int resId) {
return true;
}
private void sendChar(int c) {
try {
mTermOut.write(c);
} catch (IOException ex) {
}
}
private void sendText(CharSequence text) {
int n = text.length();
try {
for(int i = 0; i < n; i++) {
char c = text.charAt(i);
mTermOut.write(c);
}
} catch (IOException e) {
}
}
};
}
public boolean getKeypadApplicationMode() { public boolean getKeypadApplicationMode() {
return mEmulator.getKeypadApplicationMode(); return mEmulator.getKeypadApplicationMode();
} }

View File

@@ -19,8 +19,8 @@
# #
# host tools from out/host/$(HOST_OS)-$(HOST_ARCH)/ # host tools from out/host/$(HOST_OS)-$(HOST_ARCH)/
bin/aapt tools/aapt bin/aapt platforms/${PLATFORM_NAME}/tools/aapt
bin/aidl tools/aidl bin/aidl platforms/${PLATFORM_NAME}/tools/aidl
bin/adb tools/adb bin/adb tools/adb
bin/sqlite3 tools/sqlite3 bin/sqlite3 tools/sqlite3
bin/dmtracedump tools/dmtracedump bin/dmtracedump tools/dmtracedump
@@ -66,11 +66,12 @@ development/samples/NotePad platforms/${PLATFORM_NAME}/samples/NotePad
development/samples/ApiDemos platforms/${PLATFORM_NAME}/samples/ApiDemos development/samples/ApiDemos platforms/${PLATFORM_NAME}/samples/ApiDemos
development/samples/SkeletonApp platforms/${PLATFORM_NAME}/samples/SkeletonApp development/samples/SkeletonApp platforms/${PLATFORM_NAME}/samples/SkeletonApp
development/samples/Snake platforms/${PLATFORM_NAME}/samples/Snake development/samples/Snake platforms/${PLATFORM_NAME}/samples/Snake
development/samples/SoftKeyboard platforms/${PLATFORM_NAME}/samples/SoftKeyboard
# dx # dx
bin/dx tools/dx bin/dx platforms/${PLATFORM_NAME}/tools/dx
bin/dexdump tools/dexdump bin/dexdump platforms/${PLATFORM_NAME}/tools/dexdump
framework/dx.jar tools/lib/dx.jar framework/dx.jar platforms/${PLATFORM_NAME}/tools/lib/dx.jar
#androidprefs #androidprefs
framework/androidprefs.jar tools/lib/androidprefs.jar framework/androidprefs.jar tools/lib/androidprefs.jar
@@ -126,7 +127,7 @@ system.img platforms/${PLATFORM_NAME}/images/system.img
ramdisk.img platforms/${PLATFORM_NAME}/images/ramdisk.img ramdisk.img platforms/${PLATFORM_NAME}/images/ramdisk.img
userdata.img platforms/${PLATFORM_NAME}/images/userdata.img userdata.img platforms/${PLATFORM_NAME}/images/userdata.img
prebuilt/android-arm/kernel/kernel-qemu platforms/${PLATFORM_NAME}/images/kernel-qemu prebuilt/android-arm/kernel/kernel-qemu platforms/${PLATFORM_NAME}/images/kernel-qemu
external/qemu/android/vm/hardware-properties.ini tools/lib/hardware-properties.ini external/qemu/android/avd/hardware-properties.ini tools/lib/hardware-properties.ini
# emulator skins # emulator skins
development/emulator/skins/HVGA platforms/${PLATFORM_NAME}/skins/HVGA development/emulator/skins/HVGA platforms/${PLATFORM_NAME}/skins/HVGA
@@ -138,7 +139,7 @@ development/emulator/skins/QVGA-P platforms/${PLATFORM_NAME}/skins/QVGA-P
# NOTICE files are copied by build/core/Makefile # NOTICE files are copied by build/core/Makefile
# the readme # the readme
development/docs/SDK_RELEASE_NOTES RELEASE_NOTES.txt development/docs/SDK_RELEASE_NOTES RELEASE_NOTES.html
# the docs # the docs
docs/offline-sdk docs docs/offline-sdk docs

View File

@@ -15,6 +15,10 @@
set -e # Fail this script as soon as a command fails -- fail early, fail fast set -e # Fail this script as soon as a command fails -- fail early, fail fast
# Set to 1 to force removal of old unzipped SDK. Only disable for debugging, as it
# will make some rm/mv commands to fail.
FORCE="1"
SDK_ZIP="$1" SDK_ZIP="$1"
DIST_DIR="$2" DIST_DIR="$2"
@@ -81,12 +85,25 @@ function package() {
DEST_NAME_ZIP="${DEST_NAME}.zip" DEST_NAME_ZIP="${DEST_NAME}.zip"
# Unzip current linux/mac SDK and rename using the windows name # Unzip current linux/mac SDK and rename using the windows name
if [[ -n "$FORCE" || ! -d "$DEST" ]]; then
[ -e "$DEST" ] && rm -rfv "$DEST" # cleanup dest first if exists [ -e "$DEST" ] && rm -rfv "$DEST" # cleanup dest first if exists
UNZIPPED=`basename "$SDK_ZIP"` UNZIPPED=`basename "$SDK_ZIP"`
UNZIPPED="$DIST_DIR/${UNZIPPED/.zip/}" UNZIPPED="$DIST_DIR/${UNZIPPED/.zip/}"
[ -e "$UNZIPPED" ] && rm -rfv "$UNZIPPED" # cleanup unzip dir (if exists) [ -e "$UNZIPPED" ] && rm -rfv "$UNZIPPED" # cleanup unzip dir (if exists)
unzip "$SDK_ZIP" -d "$DIST_DIR" unzip "$SDK_ZIP" -d "$DIST_DIR"
mv -v "$UNZIPPED" "$DEST" mv -v "$UNZIPPED" "$DEST"
fi
# Assert that the package contains only one platform
PLATFORMS="$DEST/platforms"
THE_PLATFORM=`echo $PLATFORMS/*`
PLATFORM_TOOLS=$THE_PLATFORM/tools
echo "Platform found: " $THE_PLATFORM
[[ -d "$THE_PLATFORM" ]] || die \
"Error: One platform was expected in $SDK_ZIP. " \
"Instead found " $THE_PLATFORM
[[ -d "$PLATFORM_TOOLS" ]] || die "Missing folder $PLATFORM_TOOLS."
# USB Driver for ADB # USB Driver for ADB
mkdir -pv $DEST/usb_driver/x86 mkdir -pv $DEST/usb_driver/x86
@@ -94,25 +111,26 @@ function package() {
mkdir -pv $DEST/usb_driver/amd64 mkdir -pv $DEST/usb_driver/amd64
cp -rv development/host/windows/prebuilt/usb/driver_amd_64/* $DEST/usb_driver/amd64/ cp -rv development/host/windows/prebuilt/usb/driver_amd_64/* $DEST/usb_driver/amd64/
# Remove obsolete stuff from tools # Remove obsolete stuff from tools & platform
TOOLS="$DEST/tools" TOOLS="$DEST/tools"
LIB="$DEST/tools/lib" LIB="$DEST/tools/lib"
rm -v "$TOOLS"/{aapt,aidl,adb,emulator,traceview,draw9patch,hierarchyviewer,dx,dexdump,apkbuilder,ddms,dmtracedump,mksdcard,sqlite3,android} rm -v "$TOOLS"/{adb,emulator,traceview,draw9patch,hierarchyviewer,apkbuilder,ddms,dmtracedump,mksdcard,sqlite3,android}
rm -v --force "$LIB"/*.so "$LIB"/*.jnilib rm -v --force "$LIB"/*.so "$LIB"/*.jnilib
rm -v "$PLATFORM_TOOLS"/{aapt,aidl,dx,dexdump}
# Copy all the new stuff in tools # Copy all the new stuff in tools
# Note: some tools are first copied here and then moved in platforms/<name>/tools/
cp -v out/host/windows-x86/bin/*.{exe,dll} "$TOOLS" cp -v out/host/windows-x86/bin/*.{exe,dll} "$TOOLS"
cp -v prebuilt/windows/swt/*.{jar,dll} "$LIB" cp -v prebuilt/windows/swt/*.{jar,dll} "$LIB"
# Do we want the emulator NOTICE in the tools dir? Cf http://b/930608.
# If yes, uncomment the following line:
# cp -v external/qemu/NOTICE "$TOOLS"/emulator_NOTICE.txt
# If you want the emulator NOTICE in the tools dir, uncomment the following line:
# cp -v external/qemu/NOTICE "$TOOLS"/emulator_NOTICE.txt
# We currently need libz from MinGW for aapt # We currently need libz from MinGW for aapt
cp -v /cygdrive/c/cygwin/bin/mgwz.dll "$TOOLS" cp -v /cygdrive/c/cygwin/bin/mgwz.dll "$TOOLS"
# Update a bunch of bat files # Update a bunch of bat files
cp -v dalvik/dx/etc/dx.bat "$TOOLS"
cp -v development/tools/apkbuilder/etc/apkbuilder.bat "$TOOLS" cp -v development/tools/apkbuilder/etc/apkbuilder.bat "$TOOLS"
cp -v development/tools/ddms/app/etc/ddms.bat "$TOOLS" cp -v development/tools/ddms/app/etc/ddms.bat "$TOOLS"
cp -v development/tools/traceview/etc/traceview.bat "$TOOLS" cp -v development/tools/traceview/etc/traceview.bat "$TOOLS"
@@ -120,8 +138,15 @@ function package() {
cp -v development/tools/draw9patch/etc/draw9patch.bat "$TOOLS" cp -v development/tools/draw9patch/etc/draw9patch.bat "$TOOLS"
cp -v development/tools/sdkmanager/app/etc/android.bat "$TOOLS" cp -v development/tools/sdkmanager/app/etc/android.bat "$TOOLS"
# Copy or move platform specific tools to the default platform.
cp -v dalvik/dx/etc/dx.bat "$PLATFORM_TOOLS"
# Note: mgwz.dll must be in same folder than aapt.exe
mv -v "$TOOLS"/{aapt.exe,aidl.exe,dexdump.exe,mgwz.dll} "$PLATFORM_TOOLS"
# Fix EOL chars to make window users happy - fix all files at the top level only # Fix EOL chars to make window users happy - fix all files at the top level only
find "$DIST_DIR" -maxdepth 1 -type f -print | xargs unix2dos -D # as well as all batch files including those in platforms/<name>/tools/
find "$DIST_DIR" -maxdepth 1 -type f -writable -print0 | xargs -0 unix2dos -D
find "$DIST_DIR" -maxdepth 3 -name "*.bat" -type f -writable -print0 | xargs -0 unix2dos -D
# Done.. Zip it # Done.. Zip it
pushd "$DIST_DIR" > /dev/null pushd "$DIST_DIR" > /dev/null
@@ -131,6 +156,11 @@ function package() {
echo "Done" echo "Done"
echo echo
echo "Resulting SDK is in $DIST_DIR/$DEST_NAME_ZIP" echo "Resulting SDK is in $DIST_DIR/$DEST_NAME_ZIP"
# We want fastboot and adb next to the new SDK
for i in fastboot.exe adb.exe AdbWinApi.dll; do
mv -vf out/host/windows-x86/bin/$i "$DIST_DIR"/$i
done
} }
check check

View File

@@ -50,6 +50,7 @@ public class MonkeySourceRandom implements MonkeyEventSource{
KeyEvent.KEYCODE_HOME, KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_HOME, KeyEvent.KEYCODE_BACK,
KeyEvent.KEYCODE_CALL, KeyEvent.KEYCODE_ENDCALL, KeyEvent.KEYCODE_CALL, KeyEvent.KEYCODE_ENDCALL,
KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN,
KeyEvent.KEYCODE_MUTE,
}; };
/** Nice names for all key events. */ /** Nice names for all key events. */
private static final String[] KEY_NAMES = { private static final String[] KEY_NAMES = {
@@ -144,6 +145,7 @@ public class MonkeySourceRandom implements MonkeyEventSource{
"KEYCODE_PREVIOUSSONG", "KEYCODE_PREVIOUSSONG",
"KEYCODE_REWIND", "KEYCODE_REWIND",
"KEYCODE_FORWARD", "KEYCODE_FORWARD",
"KEYCODE_MUTE",
"TAG_LAST_KEYCODE" // EOL. used to keep the lists in sync "TAG_LAST_KEYCODE" // EOL. used to keep the lists in sync
}; };

10
data/etc/vold.conf Normal file
View File

@@ -0,0 +1,10 @@
## vold configuration file for the emulator/SDK
volume_sdcard {
## This is the direct uevent device path to the SD slot on the device
emu_media_path /devices/platform/goldfish_mmc.0/mmc_host/mmc0
media_type mmc
mount_point /sdcard
ums_path /devices/platform/usb_mass_storage/lun0
}

View File

@@ -1,7 +1,8 @@
For the latest Known Issues and Changes, please visit: <html>
<head>
http://code.google.com/android/RELEASENOTES.html <meta http-equiv="refresh" content="0;url=docs/sdk/1.1_r1/index.html">
</head>
For information on how to install the Android SDK, please visit: <body>
<a href="docs/sdk/1.1_r1/index.html">click here if you are not redirected</a>
http://code.google.com/android/intro/installing.html </body>
</html>

View File

@@ -0,0 +1,7 @@
key 164 PLAYPAUSE WAKE
key 128 STOP WAKE
key 163 NEXTSONG WAKE
key 165 PREVIOUSSONG WAKE
key 168 REWIND WAKE
key 159 FORWARD WAKE

View File

@@ -11,3 +11,8 @@ file := $(TARGET_OUT_KEYLAYOUT)/qwerty.kl
ALL_PREBUILT += $(file) ALL_PREBUILT += $(file)
$(file): $(LOCAL_PATH)/qwerty.kl | $(ACP) $(file): $(LOCAL_PATH)/qwerty.kl | $(ACP)
$(transform-prebuilt-to-target) $(transform-prebuilt-to-target)
file := $(TARGET_OUT_KEYLAYOUT)/AVRCP.kl
ALL_PREBUILT += $(file)
$(file) : $(LOCAL_PATH)/AVRCP.kl | $(ACP)
$(transform-prebuilt-to-target)

Binary file not shown.

Binary file not shown.

View File

@@ -10,7 +10,7 @@ Signature="$WINDOWS NT$"
Class=USB Class=USB
ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B} ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
Provider=%GOOG% Provider=%GOOG%
DriverVer=12/11/2008,1.0.0009.00000 DriverVer=1/29/2009,1.0.0010.00000
CatalogFile.NTx86=androidusb86.cat CatalogFile.NTx86=androidusb86.cat
CatalogFile.NTamd64=androidusba64.cat CatalogFile.NTamd64=androidusba64.cat
@@ -38,6 +38,7 @@ DefaultDestDir = 12
; HTC Dream ; HTC Dream
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 %USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 %USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
; For XP and later ; For XP and later
[Google.NTx86] [Google.NTx86]
@@ -46,6 +47,7 @@ DefaultDestDir = 12
; HTC Dream ; HTC Dream
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 %USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 %USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
; For AMD64 and later ; For AMD64 and later
[Google.NTamd64] [Google.NTamd64]
@@ -54,6 +56,7 @@ DefaultDestDir = 12
; HTC Dream ; HTC Dream
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 %USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 %USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
[androidusb.Dev.NT] [androidusb.Dev.NT]
CopyFiles=androidusb.Files.Ext CopyFiles=androidusb.Files.Ext
@@ -120,3 +123,4 @@ ClassName = "ADB Interface"
USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface" USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface"
USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream" USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream"
USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface" USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface"
USB\VID_0BB4&PID_0FFF.DeviceDescRelease="HTC Bootloader"

View File

@@ -10,7 +10,7 @@ Signature="$WINDOWS NT$"
Class=USB Class=USB
ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B} ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
Provider=%GOOG% Provider=%GOOG%
DriverVer=12/11/2008,1.0.0009.00000 DriverVer=1/29/2009,1.0.0010.00000
CatalogFile.NTx86=androidusb86.cat CatalogFile.NTx86=androidusb86.cat
CatalogFile.NTamd64=androidusba64.cat CatalogFile.NTamd64=androidusba64.cat
@@ -38,6 +38,7 @@ DefaultDestDir = 12
; HTC Dream ; HTC Dream
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 %USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 %USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
; For XP and later ; For XP and later
[Google.NTx86] [Google.NTx86]
@@ -46,6 +47,7 @@ DefaultDestDir = 12
; HTC Dream ; HTC Dream
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 %USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 %USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
; For AMD64 and later ; For AMD64 and later
[Google.NTamd64] [Google.NTamd64]
@@ -54,6 +56,7 @@ DefaultDestDir = 12
; HTC Dream ; HTC Dream
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 %USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 %USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
[androidusb.Dev.NT] [androidusb.Dev.NT]
CopyFiles=androidusb.Files.Ext CopyFiles=androidusb.Files.Ext
@@ -120,3 +123,4 @@ ClassName = "ADB Interface"
USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface" USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface"
USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream" USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream"
USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface" USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface"
USB\VID_0BB4&PID_0FFF.DeviceDescRelease="HTC Bootloader"

View File

@@ -106,7 +106,7 @@ bool AdbInterfaceObject::GetSerialNumber(void* buffer,
// Open USB device for this intefface // Open USB device for this intefface
HANDLE usb_device_handle = CreateFile(interface_name().c_str(), HANDLE usb_device_handle = CreateFile(interface_name().c_str(),
FILE_READ_ATTRIBUTES | FILE_READ_EA, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, NULL,
OPEN_EXISTING, OPEN_EXISTING,
@@ -208,7 +208,7 @@ bool AdbInterfaceObject::GetEndpointInformation(UCHAR endpoint_index,
// Open USB device for this intefface // Open USB device for this intefface
HANDLE usb_device_handle = CreateFile(interface_name().c_str(), HANDLE usb_device_handle = CreateFile(interface_name().c_str(),
FILE_READ_ATTRIBUTES | FILE_READ_EA, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, NULL,
OPEN_EXISTING, OPEN_EXISTING,

View File

@@ -10,7 +10,7 @@ Signature="$WINDOWS NT$"
Class=USB Class=USB
ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B} ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
Provider=%GOOG% Provider=%GOOG%
DriverVer=12/11/2008,1.0.0009.00000 DriverVer=1/29/2009,1.0.0010.00000
CatalogFile.NTx86=androidusb86.cat CatalogFile.NTx86=androidusb86.cat
CatalogFile.NTamd64=androidusba64.cat CatalogFile.NTamd64=androidusba64.cat
@@ -38,6 +38,7 @@ DefaultDestDir = 12
; HTC Dream ; HTC Dream
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 %USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 %USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
; For XP and later ; For XP and later
[Google.NTx86] [Google.NTx86]
@@ -46,6 +47,7 @@ DefaultDestDir = 12
; HTC Dream ; HTC Dream
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 %USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 %USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
; For AMD64 and later ; For AMD64 and later
[Google.NTamd64] [Google.NTamd64]
@@ -54,6 +56,7 @@ DefaultDestDir = 12
; HTC Dream ; HTC Dream
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 %USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 %USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
[androidusb.Dev.NT] [androidusb.Dev.NT]
CopyFiles=androidusb.Files.Ext CopyFiles=androidusb.Files.Ext
@@ -120,3 +123,4 @@ ClassName = "ADB Interface"
USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface" USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface"
USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream" USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream"
USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface" USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface"
USB\VID_0BB4&PID_0FFF.DeviceDescRelease="HTC Bootloader"

View File

@@ -19,7 +19,6 @@
<classpathentry kind="src" path="packages/apps/Settings/src"/> <classpathentry kind="src" path="packages/apps/Settings/src"/>
<classpathentry kind="src" path="packages/apps/SoundRecorder/src"/> <classpathentry kind="src" path="packages/apps/SoundRecorder/src"/>
<classpathentry kind="src" path="packages/apps/Stk/src"/> <classpathentry kind="src" path="packages/apps/Stk/src"/>
<classpathentry kind="src" path="packages/apps/Sync/src"/>
<classpathentry kind="src" path="packages/apps/Updater/src"/> <classpathentry kind="src" path="packages/apps/Updater/src"/>
<classpathentry kind="src" path="packages/apps/VoiceDialer/src"/> <classpathentry kind="src" path="packages/apps/VoiceDialer/src"/>
<classpathentry kind="src" path="packages/providers/CalendarProvider/src"/> <classpathentry kind="src" path="packages/providers/CalendarProvider/src"/>

View File

@@ -16,7 +16,6 @@
# Assemble the Platform Development Kit (PDK) # Assemble the Platform Development Kit (PDK)
# (TODO) Figure out why $(ACP) builds with target ndk but not pdk_docs # (TODO) Figure out why $(ACP) builds with target ndk but not pdk_docs
# (TODO) Copy over index.html from templates instead of from generatedDocs
# (TODO) Build doxygen (depend on latest version) # (TODO) Build doxygen (depend on latest version)
pdk: pdk:
@@ -37,14 +36,15 @@ include $(LOCAL_PATH)/ndk/Ndk.mk
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Make the Plaftorm Development Kit Documentation. # Make the Plaftorm Development Kit Documentation.
# Doxygenize the header files to create html docs in the generatedDocs dir. # Doxygenize the header files to create html docs in the generatedDocs dir.
# Copy the template files and the generated html to the docs dir and zip # Copy the appengine files, the template files and the generated html
# everything up to the distribution directory. # to the docs dir and zip everything up to the distribution directory.
# Workspace directory # Workspace directory
pdk_docs_intermediates := $(call intermediates-dir-for,PACKAGING,pdkdocs) pdk_docs_intermediates := $(call intermediates-dir-for,PACKAGING,pdkdocs)
# Source directories for templates, config & header files # Source directories for appengine, templates, config & header files
pdk_hosting_dir := development/pdk/hosting
pdk_templates_dir := development/pdk/docs pdk_templates_dir := development/pdk/docs
pdk_config_dir := development/pdk/doxygen_config pdk_config_dir := development/pdk/doxygen_config
pdk_docsfile_dir := $(pdk_config_dir)/docsfiles pdk_docsfile_dir := $(pdk_config_dir)/docsfiles
@@ -140,6 +140,16 @@ $(pdk_doxy_docsfiles_dir)/main.dox: $(pdk_docsfile_dir)/main.dox
@echo "PDK: $@" @echo "PDK: $@"
$(copy-file-to-target-with-cp) $(copy-file-to-target-with-cp)
# Copy appengine server files
$(pdk_docs_intermediates)/app.yaml: $(pdk_hosting_dir)/app.yaml
@echo "PDK: $@"
$(copy-file-to-target-with-cp)
$(pdk_docs_intermediates)/pdk.py: $(pdk_hosting_dir)/pdk.py
@echo "PDK: $@"
$(copy-file-to-target-with-cp)
# Run doxygen and copy all output and templates to the final destination # Run doxygen and copy all output and templates to the final destination
# We replace index.html with a template file so don't use the generated one # We replace index.html with a template file so don't use the generated one
pdk_doxygen: all_copied_pdk_headers $(pdk_doxygen_config_override_file) \ pdk_doxygen: all_copied_pdk_headers $(pdk_doxygen_config_override_file) \
@@ -178,11 +188,12 @@ $(call dist-for-goals,pdk_docs,$(pdk_docs_tarfile_zipped))
$(hide) gzip -cf $< > $@ $(hide) gzip -cf $< > $@
# tar up all the files to make the pdk docs. # tar up all the files to make the pdk docs.
$(pdk_docs_tarfile): pdk_doxygen all_copied_pdk_templates $(pdk_docs_tarfile): pdk_doxygen all_copied_pdk_templates \
$(pdk_docs_intermediates)/pdk.py $(pdk_docs_intermediates)/app.yaml
@echo "PDK: $@" @echo "PDK: $@"
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
@rm -f $@ @rm -f $@
$(hide) tar rf $@ -C $(pdk_docs_intermediates) docs $(hide) tar rf $@ -C $(pdk_docs_intermediates) docs pdk.py app.yaml
# Debugging reporting can go here, add it as a target to get output. # Debugging reporting can go here, add it as a target to get output.
pdk_debug: pdk_debug:

View File

@@ -70,3 +70,9 @@ The build target 'pdk' brings in the pdk/ndk make files into the build system.
for doxygen version changing you can pass in the variable: for doxygen version changing you can pass in the variable:
doxygen_version='<path/name_of_doxygen_executable>' doxygen_version='<path/name_of_doxygen_executable>'
on the make line. on the make line.
--------------------------------------------------------------------------------
To host the pdk docs on appengine run:
/home/build/static/projects/apphosting/devtools/appcfg.py update pdk/
where the pdk directory contains: pdk.py, app.yaml, and the docs directory,
all of which are tarred up by the Pdk.mk file when using the targer pdk_docs.

View File

@@ -200,7 +200,7 @@ h1,h2,h3 {
<a href="#androidTestingLocationFiles">Location of Files</a><br/> <a href="#androidTestingLocationFiles">Location of Files</a><br/>
<a href="#androidTestingContentMakefile">Contents of makefile</a><br/> <a href="#androidTestingContentMakefile">Contents of makefile</a><br/>
<a href="#androidTestingContentManifest">Content of Manifest</a><br/> <a href="#androidTestingContentManifest">Content of Manifest</a><br/>
<a href="#androidInstrumentationTestingCreatingTestRunner">New Instrumentation TestRunner</a><br/> <a href="#androidInstrumentationTestingCreatingTestRunner">New InstrumentationTestRunner</a><br/>
<a href="#androidInstrumentationTestingCreatingTestCase">New InstrumentationTestCase</a><br/> <a href="#androidInstrumentationTestingCreatingTestCase">New InstrumentationTestCase</a><br/>
<a href="#androidInstrumentationFrameworkTestCase">Exploring a Test Case</a><br/> <a href="#androidInstrumentationFrameworkTestCase">Exploring a Test Case</a><br/>
<a href="#androidTestingKindsofTests">Deciding Kinds of Tests to Write</a><br/></div> <a href="#androidTestingKindsofTests">Deciding Kinds of Tests to Write</a><br/></div>
@@ -493,22 +493,27 @@ include $(BUILD_PACKAGE)
<a name="androidTestingContentManifest"></a><h3>Content of Manifest</h3> <a name="androidTestingContentManifest"></a><h3>Content of Manifest</h3>
<p>Use the following example to create an <code>AndroidManifest.xml</code> file that declares the instrumentation. Specify that the framework supplied Instrumentation TestRunner targest the package of your application, allowing the tests that are run with the instrumentation to get access to all of the classes of your application without having to build the source into the test app. The name of the test application is typically the same as your target application with <code>.tests</code> appended. </p> <p>Use the following example to create an <code>AndroidManifest.xml</code> file that declares the instrumentation. Specify that the framework supplied InstrumentationTestRunner targets the package of your application, allowing the tests that are run with the instrumentation to get access to all of the classes of your application without having to build the source into the test app. The name of the test application is typically the same as your target application with <code>.tests</code> appended. </p>
<pre> <pre>
# Add appropriate copyright banner here # Add appropriate copyright banner here
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android" &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.samples.tests"&gt; package="com.example.android.apis.tests"&gt;
&lt;uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /&gt; &lt;!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
which is needed when building test cases. -->
&lt;application>
&lt;uses-library android:name="android.test.runner" />
&lt;/application>
&lt;!-- &lt;!--
This declares that this app uses the instrumentation test runner targeting This declares that this app uses the instrumentation test runner targeting
the package of com.android.samples. To run the tests use the command: the package of com.example.android.apis. To run the tests use the command:
"adb shell am instrument -w com.android.samples.tests/android.test.InstrumentationTestRunner" "adb shell am instrument -w com.example.android.apis.tests/android.test.InstrumentationTestRunner"
--&gt; -->
&lt;instrumentation android:name="android.test.InstrumentationTestRunner" &lt;instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.samples" android:targetPackage="com.example.android.apis"
android:label="Tests for Api Demos."/&gt; android:label="Tests for Api Demos."/>
&lt;/manifest&gt; &lt;/manifest&gt;
</pre> </pre>
@@ -520,7 +525,7 @@ $ adb shell am instrument -w \
</pre> </pre>
<a name="androidInstrumentationTestingCreatingTestRunner"></a><h3>New Instrumentation TestRunner</h3> <a name="androidInstrumentationTestingCreatingTestRunner"></a><h3>New InstrumentationTestRunner</h3>
<p>Create a class that derives from this class. You must override two abstract methods; one that returns the class loader of the target package, and another that defines all of the tests within the package. For example, the snippet below displays the test runner for the framework tests.</p> <p>Create a class that derives from this class. You must override two abstract methods; one that returns the class loader of the target package, and another that defines all of the tests within the package. For example, the snippet below displays the test runner for the framework tests.</p>
<pre class="prettify"> <pre class="prettify">
@@ -544,8 +549,6 @@ public class FrameworkInstrumentationTestRunner extends InstrumentationTestRunne
</pre> </pre>
<p> Next, in an appropriate <code>AndroidManifest.xml</code>, define the instrumentation for the derived class with the appropriate <code>android:targetPackage</code> set. For example, the snippet below defines the instrumentation runner for the framework tests.</p> <p> Next, in an appropriate <code>AndroidManifest.xml</code>, define the instrumentation for the derived class with the appropriate <code>android:targetPackage</code> set. For example, the snippet below defines the instrumentation runner for the framework tests.</p>
<pre class="prettify"> <pre class="prettify">
&lt;uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /&gt;
&lt;instrumentation android:name="android.tests.FrameworkInstrumentationTestRunner" &lt;instrumentation android:name="android.tests.FrameworkInstrumentationTestRunner"
android:targetPackage="com.google.android.frameworktest" android:targetPackage="com.google.android.frameworktest"
android:label="framework instrumentation test runner" /&gt; android:label="framework instrumentation test runner" /&gt;

19
pdk/docs/templates/footer.cs vendored Executable file
View File

@@ -0,0 +1,19 @@
<div id="footer">
<?cs if:reference||guide ?>
<div id="copyright">
<?cs call:custom_copyright() ?>
</div>
<div id="build_info">
<?cs call:custom_buildinfo() ?>
</div>
<?cs elif:!hide_license_footer ?>
<div id="copyright">
<?cs call:custom_cc_copyright() ?>
</div>
<?cs /if ?>
<div id="footerlinks">
<?cs call:custom_footerlinks() ?>
</div>
</div> <!-- end footer -->

37
pdk/docs/templates/head_tag.cs vendored Executable file
View File

@@ -0,0 +1,37 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="shortcut icon" type="image/x-icon" href="<?cs var:toroot ?>favicon.ico" />
<title><?cs
if:page.title ?><?cs
var:page.title ?><?cs
if:sdk.version ?> (<?cs
var:sdk.version ?>)<?cs
/if ?> | <?cs
/if ?>Android Developers</title><?cs
if:guide||sdk ?>
<link href="<?cs var:toroot ?>assets/android-developer-docs-devguide.css" rel="stylesheet" type="text/css" /><?cs
else ?>
<link href="<?cs var:toroot ?>assets/android-developer-docs.css" rel="stylesheet" type="text/css" /><?cs
/if ?>
<script src="<?cs var:toroot ?>assets/search_autocomplete.js" type="text/javascript"></script>
<script src="<?cs var:toroot ?>reference/lists.js" type="text/javascript"></script>
<script src="<?cs var:toroot ?>assets/jquery-resizable.min.js" type="text/javascript"></script>
<script src="<?cs var:toroot ?>assets/android-developer-docs.js" type="text/javascript"></script>
<script type="text/javascript">
setToRoot("<?cs var:toroot ?>");
</script><?cs
if:reference ?>
<script src="<?cs var:toroot ?>navtree_data.js" type="text/javascript"></script>
<script src="<?cs var:toroot ?>assets/navtree.js" type="text/javascript"></script><?cs
/if ?>
<noscript>
<style type="text/css">
body{overflow:auto;}
#body-content{position:relative; top:0;}
#doc-content{overflow:visible;border-left:3px solid #666;}
#side-nav{padding:0;}
#side-nav .toggle-list ul {display:block;}
#resize-packages-nav{border-bottom:3px solid #666;}
</style>
</noscript>
</head>

3
pdk/docs/templates/header.cs vendored Executable file
View File

@@ -0,0 +1,3 @@
<?cs call:custom_masthead() ?>
<?cs call:custom_left_nav() ?>

8
pdk/docs/templates/index.cs vendored Executable file
View File

@@ -0,0 +1,8 @@
<html>
<head>
<meta http-equiv="refresh" content="0;url=packages.html">
</head>
<body>
<?cs include:"analytics.cs" ?>
</body>
</html>

11
pdk/docs/templates/trailer.cs vendored Executable file
View File

@@ -0,0 +1,11 @@
</div> <!-- end body-content --> <?cs # normally opened by header.cs ?>
<script type="text/javascript">
init(); /* initialize android-developer-docs.js */
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-5831155-1");
pageTracker._trackPageview();
</script>

11
pdk/hosting/app.yaml Normal file
View File

@@ -0,0 +1,11 @@
application: pdk-docs
version: 1
runtime: python
api_version: 1
handlers:
- url: /docs
static_dir: docs
- url: /
script: pdk.py

44
pdk/hosting/pdk.py Normal file
View File

@@ -0,0 +1,44 @@
#!/usr/bin/python2.5
#
# Copyright (C) 2008 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.
#
"""Serve static pages for the pdk on appengine
"""
import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
class MainPage(webapp.RequestHandler):
def get(self):
self.redirect('docs/index.html')
application = webapp.WSGIApplication(
[('/', MainPage)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
# To upload this application:
# /home/build/static/projects/apphosting/devtools/appcfg.py update pdk/
# where the pdk directory contains: pdk.py, app.yaml, and the docs directory.
# where the docs are made from the Pdk.mk file.

View File

@@ -0,0 +1,741 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<base target="_top">
<style type="text/css">
/* default css */
table {
font-size: 1em;
line-height: inherit;
}
tr {
text-align: left;
}
div, address, ol, ul, li, option, select {
margin-top: 0px;
margin-bottom: 0px;
}
p {
margin: 0px;
}
body {
margin: 6px;
padding: 0px;
font-family: Verdana, sans-serif;
font-size: 10pt;
background-color: #ffffff;
}
img {
-moz-force-broken-image-icon: 1;
}
@media screen {
html.pageview {
background-color: #f3f3f3 !important;
}
body {
min-height: 1100px;
counter-reset: __goog_page__;
}
* html body {
height: 1100px;
}
.pageview body {
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
border-right: 2px solid #bbb;
border-bottom: 2px solid #bbb;
width: 648px !important;
margin: 15px auto 25px;
padding: 40px 50px;
}
/* IE6 */
* html {
overflow-y: scroll;
}
* html.pageview body {
overflow-x: auto;
}
/* Prevent repaint errors when scrolling in Safari. This "Star-7" css hack
targets Safari 3.1, but not WebKit nightlies and presumably Safari 4.
That's OK because this bug is fixed in WebKit nightlies/Safari 4 :-). */
html*#wys_frame::before {
content: '\A0';
position: fixed;
overflow: hidden;
width: 0;
height: 0;
top: 0;
left: 0;
}
.writely-callout-data {
display: none;
*display: inline-block;
*width: 0;
*height: 0;
*overflow: hidden;
}
.writely-footnote-marker {
background-image: url('MISSING');
background-color: transparent;
background-repeat: no-repeat;
width: 7px;
overflow: hidden;
height: 16px;
vertical-align: top;
-moz-user-select: none;
}
.editor .writely-footnote-marker {
cursor: move;
}
.writely-footnote-marker-highlight {
background-position: -15px 0;
-moz-user-select: text;
}
.writely-footnote-hide-selection ::-moz-selection, .writely-footnote-hide-selection::-moz-selection {
background: transparent;
}
.writely-footnote-hide-selection ::selection, .writely-footnote-hide-selection::selection {
background: transparent;
}
.writely-footnote-hide-selection {
cursor: move;
}
.editor .writely-comment-yellow {
background-color: #FF9;
background-position: -240px 0;
}
.editor .writely-comment-yellow-hover {
background-color: #FF0;
background-position: -224px 0;
}
.editor .writely-comment-blue {
background-color: #C0D3FF;
background-position: -16px 0;
}
.editor .writely-comment-blue-hover {
background-color: #6292FE;
background-position: 0 0;
}
.editor .writely-comment-orange {
background-color: #FFDEAD;
background-position: -80px 0;
}
.editor .writely-comment-orange-hover {
background-color: #F90;
background-position: -64px 0;
}
.editor .writely-comment-green {
background-color: #99FBB3;
background-position: -48px 0;
}
.editor .writely-comment-green-hover {
background-color: #00F442;
background-position: -32px 0;
}
.editor .writely-comment-cyan {
background-color: #CFF;
background-position: -208px 0;
}
.editor .writely-comment-cyan-hover {
background-color: #0FF;
background-position: -192px 0;
}
.editor .writely-comment-purple {
background-color: #EBCCFF;
background-position: -144px 0;
}
.editor .writely-comment-purple-hover {
background-color: #90F;
background-position: -128px 0;
}
.editor .writely-comment-magenta {
background-color: #FCF;
background-position: -112px 0;
}
.editor .writely-comment-magenta-hover {
background-color: #F0F;
background-position: -96px 0;
}
.editor .writely-comment-red {
background-color: #FFCACA;
background-position: -176px 0;
}
.editor .writely-comment-red-hover {
background-color: #FF7A7A;
background-position: -160px 0;
}
.editor .writely-comment-marker {
background-image: url('MISSING');
background-color: transparent;
padding-right: 11px;
background-repeat: no-repeat;
width: 16px;
height: 16px;
-moz-user-select: none;
}
.editor .writely-comment-hidden {
padding: 0;
background: none;
}
.editor .writely-comment-marker-hidden {
background: none;
padding: 0;
width: 0;
}
.editor .writely-comment-none {
opacity: .2;
filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20);
-moz-opacity: .2;
}
.editor .writely-comment-none-hover {
opacity: .2;
filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20);
-moz-opacity: .2;
}
.br_fix br:not(:-moz-last-node):not(:-moz-first-node) {
position:relative;
left: -1ex
}
.br_fix br+br {
position: static !important
}
}
h6 { font-size: 8pt }
h5 { font-size: 8pt }
h4 { font-size: 10pt }
h3 { font-size: 12pt }
h2 { font-size: 14pt }
h1 { font-size: 18pt }
blockquote {padding: 10px; border: 1px #DDD dashed }
a img {border: 0}
.pb {
border-width: 0;
page-break-after: always;
/* We don't want this to be resizeable, so enforce a width and height
using !important */
height: 1px !important;
width: 100% !important;
}
.editor .pb {
border-top: 1px dashed #C0C0C0;
border-bottom: 1px dashed #C0C0C0;
}
div.google_header, div.google_footer {
position: relative;
margin-top: 1em;
margin-bottom: 1em;
}
/* Table of contents */
.editor div.writely-toc {
background-color: #f3f3f3;
border: 1px solid #ccc;
}
.writely-toc > ol {
padding-left: 3em;
font-weight: bold;
}
ol.writely-toc-subheading {
padding-left: 1em;
font-weight: normal;
}
/* IE6 only */
* html writely-toc ol {
list-style-position: inside;
}
.writely-toc-none {
list-style-type: none;
}
.writely-toc-decimal {
list-style-type: decimal;
}
.writely-toc-upper-alpha {
list-style-type: upper-alpha;
}
.writely-toc-lower-alpha {
list-style-type: lower-alpha;
}
.writely-toc-upper-roman {
list-style-type: upper-roman;
}
.writely-toc-lower-roman {
list-style-type: lower-roman;
}
.writely-toc-disc {
list-style-type: disc;
}
/* end default css */
/* default print css */
@media print {
body {
padding: 0;
margin: 0;
}
div.google_header, div.google_footer {
display: block;
min-height: 0;
border: none;
}
div.google_header {
flow: static(header);
}
/* used to insert page numbers */
div.google_header::before, div.google_footer::before {
position: absolute;
top: 0;
}
div.google_footer {
flow: static(footer);
}
/* always consider this element at the start of the doc */
div#google_footer {
flow: static(footer, start);
}
span.google_pagenumber {
content: counter(page);
}
span.google_pagecount {
content: counter(pages);
}
callout.google_footnote {
display: prince-footnote;
footnote-style-position: inside;
/* These styles keep the footnote from taking on the style of the text
surrounding the footnote marker. They can be overridden in the
document CSS. */
color: #000;
font-family: Verdana;
font-size: 10.0pt;
font-weight: normal;
}
/* Table of contents */
#WritelyTableOfContents a::after {
content: leader('.') target-counter(attr(href), page);
}
#WritelyTableOfContents a {
text-decoration: none;
color: black;
}
}
@page {
@top {
content: flow(header);
}
@bottom {
content: flow(footer);
}
@footnotes {
border-top: solid black thin;
padding-top: 8pt;
}
}
/* end default print css */
/* custom css */
/* end custom css */
/* ui edited css */
body {
font-family: Verdana;
font-size: 10.0pt;
line-height: normal;
background-color: #ffffff;
}
/* end ui edited css */
/* editor CSS */
.editor a:visited {color: #551A8B}
.editor table.zeroBorder {border: 1px dotted gray}
.editor table.zeroBorder td {border: 1px dotted gray}
.editor table.zeroBorder th {border: 1px dotted gray}
.editor div.google_header, .editor div.google_footer {
border: 2px #DDDDDD dashed;
position: static;
width: 100%;
min-height: 2em;
}
.editor .misspell {background-color: yellow}
.editor .writely-comment {
font-size: 9pt;
line-height: 1.4;
padding: 1px;
border: 1px dashed #C0C0C0
}
/* end editor CSS */
</style>
</head>
<body onload="DoPageLoad();"
revision="cfnx2f69_111dp3jzfgb:107">
<h1>
Using the Android Native Development Kit (NDK)
</h1>
version 1.3<br>
<br>
<h2>
Introduction
</h2>
The Android Native Development Kit enables developers to write shared libraries
in C or C++ and call them from Java code. The native shared libraries can be
packaged into apk files along with a normal Android application written in Java,
so that the resulting Android application can be downloaded and installed on an
Android phone.<br>
<br>
The Native Development Kit consists of:<br>
<ul>
<li>
C/C++ headers for native APIs<br>
</li>
<li>
C/C++ libraries for native APIs<br>
</li>
<li>
Documentation
</li>
<li>
Sample Code
</li>
</ul>
<br>
The Native Development Kit is designed to be used with the Android SDK:<br>
<ul>
<li>
The NDK is used to create a shared library containing native code.
</li>
<li>
The SDK is used to create an Android application written in Java that calls
into the native code shared library.
</li>
</ul>
<h1>
</h1>
<h2>
Setting up your machine<br>
</h2>
The Native Development Kit may be installed on either Linux or OS X. Developing
under Windows is not yet supported.<br>
<div>
<h3>
Linux Installation
</h3>
The
Android&nbsp;build&nbsp;is&nbsp;routinely&nbsp;tested&nbsp;on&nbsp;recent&nbsp;versions&nbsp;of&nbsp;Ubuntu&nbsp;(6.06&nbsp;and&nbsp;later),&nbsp;but
may work on other distributions as well.<br>
<h4>
<a name=TOC-Ubuntu-Linux-i386-></a><span style=FONT-FAMILY:Verdana>Ubuntu
Linux (i386)</span>
</h4>
<div style=FONT-FAMILY:Verdana>
To set up your Linux development environment, make sure you have the
following:<span style="WORD-SPACING:0px; FONT-STYLE:normal; FONT-VARIANT:normal; FONT-WEIGHT:normal; font-size-adjust:none; font-stretch:normal; TEXT-TRANSFORM:none; COLOR:#000000; WHITE-SPACE:normal; LETTER-SPACING:normal; border-collapse:separate"><font size=2>
</font></span>
</div>
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px; FONT-FAMILY:Verdana">
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px">
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px">
<ul style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px">
<li style="MARGIN-TOP:8px; MARGIN-BOTTOM:8px">
Git 1.5.4 or
newer<span style="FONT-WEIGHT:normal; WORD-SPACING:0px; TEXT-TRANSFORM:none; COLOR:#000000; FONT-STYLE:normal; WHITE-SPACE:normal; LETTER-SPACING:normal; border-collapse:separate; FONT-VARIANT:normal"><font size=2>.&nbsp;</font></span>
</li>
</ul>
</div>
</div>
</div>
<blockquote style="BORDER:medium none ; MARGIN:0pt 0pt 0pt 40px; PADDING:0px">
<span style=FONT-FAMILY:arial><span style="FONT-WEIGHT:normal; WORD-SPACING:0px; TEXT-TRANSFORM:none; COLOR:#000000; FONT-STYLE:normal; WHITE-SPACE:normal; LETTER-SPACING:normal; border-collapse:separate; FONT-VARIANT:normal"><span style="FONT-FAMILY:courier new,monospace">$
</span></span><span style="FONT-FAMILY:courier new,monospace">sudo apt-get
install git-core<br>
</span></span>
</blockquote>
<div>
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px">
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px; FONT-FAMILY:arial,sans-serif">
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px">
<h4>
<a name=TOC-Ubuntu-Linux-amd64-></a><span style=FONT-FAMILY:Verdana>Ubuntu
Linux (amd64)</span>
</h4>
<span style=FONT-FAMILY:Verdana>This has not been as well
tested.</span>
</div>
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px; FONT-FAMILY:Verdana">
<br>
</div>
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px; FONT-FAMILY:Verdana">
The Android build requires a 32-bit build environment:
</div>
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px; FONT-FAMILY:Verdana">
<ul>
<li>
Get the packages as listed above in the i386
instructions:<span style="FONT-WEIGHT:normal; WORD-SPACING:0px; TEXT-TRANSFORM:none; COLOR:#000000; FONT-STYLE:normal; WHITE-SPACE:normal; LETTER-SPACING:normal; border-collapse:separate; FONT-VARIANT:normal">&nbsp;&nbsp;&nbsp;</span>
</li>
</ul>
</div>
</div>
</div>
</div>
<blockquote style="BORDER:medium none ; MARGIN:0pt 0pt 0pt 40px; PADDING:0px">
<span style=FONT-FAMILY:arial><span style="FONT-WEIGHT:normal; WORD-SPACING:0px; TEXT-TRANSFORM:none; COLOR:#000000; FONT-STYLE:normal; WHITE-SPACE:normal; LETTER-SPACING:normal; border-collapse:separate; FONT-VARIANT:normal"><span style="FONT-FAMILY:courier new,monospace">$&nbsp;</span></span><span style="FONT-FAMILY:courier new,monospace">sudo
apt-get install git-core<br>
</span></span>
</blockquote>
<h4>
<a name=TOC-Other-Linux></a>Other Linux
</h4>
<p>
There's
no&nbsp;reason&nbsp;why&nbsp;Android&nbsp;cannot&nbsp;be&nbsp;built&nbsp;on&nbsp;non-Ubuntu&nbsp;systems<span style=FONT-WEIGHT:normal><font size=2>.&nbsp;In&nbsp;general&nbsp;you&nbsp;will&nbsp;need:</font></span>
</p>
<ul>
<li>
Git&nbsp;1.5.4&nbsp;or&nbsp;newer.&nbsp;You&nbsp;can&nbsp;find&nbsp;it&nbsp;at&nbsp;<a href=http://git.or.cz/ rel=nofollow>http://git.or.cz/</a><span style=FONT-FAMILY:arial></span>
</li>
</ul>
<div>
<h3>
Mac OS Installation
</h3>
<ul>
<li>
<span style=FONT-FAMILY:arial,sans-serif>To build the Android files in a
Mac OS environment, you need an Intel/x86 machine. The Android build
system and tools do not support the older PowerPC architecture.</span>
</li>
<li>
<span style=FONT-FAMILY:arial,sans-serif>Android must be built on a
case-sensitive file system.<br>
</span>
</li>
<ul>
<li>
We recommend that you build Android on a partition that has been
formatted with the "Case-sensitive Journaled HFS+" file system:
</li>
<ul>
<li>
A case-sensitive file system is required because the sources contain
files that differ only in case.
</li>
<li>
Journaled systems are more robust. (This is optional, but
recommended.)
</li>
<li>
HFS+ is required to successfully build Mac OS applications such as
the Android Emulator for OS X.
</li>
</ul>
<li>
If you want to avoid partitioning/formatting your hard drive, you can
use a case-sensitive disk image instead.
</li>
<ul>
<li>
To create the image:<br>
<ul>
<li>
launch /Applications/Utilities/Disk Utility
</li>
<li>
select "New Image"
</li>
<li>
size: 8 GB (this will work, but you can choose more if you want
to)
</li>
<li>
volume format: case sensitive, journaled
</li>
</ul>
</li>
<li>
This will create a .dmg file which, once mounted, acts as a drive
with the required formatting for Android development. For a disk
image named "android.dmg" stored in your home directory, you can add
the following to your ~/.bash_profile to mount the image when you
execute "mountAndroid":<br>
<br>
<div style=MARGIN-LEFT:40px>
<span style="FONT-FAMILY:courier new,monospace"># command to mount
the android file
image</span><br style="FONT-FAMILY:courier new,monospace">
<span style="FONT-FAMILY:courier new,monospace">function
mountAndroid&nbsp; { hdiutil attach ~/android.dmg&nbsp;
-mountpoint /Volumes/android; }</span><br>
</div>
<br>
Once mounted, you'll do all your work in the "android" volume. You
can eject it (unmount it) just like you would with an external
drive.
</li>
</ul>
</ul>
</ul>
<div>
<br>
<ul>
<li>
Install git 1.5.4 or newer. You can find it at
<a href=http://git.or.cz/ rel=nofollow>http://git.or.cz/</a>
</li>
</ul>
<h2>
Installing the Android SDK
</h2>
The Android NDK uses the Android SDK.&nbsp;You can find the Android SDK at
<a href=http://code.google.com/android/download.html id=a.-o title=http://code.google.com/android/download.html>http://code.google.com/android/download.html</a><br>
This version of the Android NDK requires the Cupcake version of the
Android SDK.<br>
<br>
<h2>
Installing the Prebuilt Native Toolchain<br>
</h2>
The NDK uses the prebuilt native toolchain from the Android Open Source
git repository.<br>
<br>
To download the prebuilt native toolchain to your working directory,
execute the following commands:<br>
<br>
<span style="FONT-FAMILY:Courier New"></span>
<div style=MARGIN-LEFT:40px>
<span style="FONT-FAMILY:Courier New">git clone
git://android.git.kernel.org/platform/prebuilt.git</span><br>
<span style="FONT-FAMILY:Courier New">cd prebuilt</span><br>
<span style="FONT-FAMILY:Courier New">git checkout -b cupcake -t
origin/cupcake</span><br>
</div>
<div style=MARGIN-LEFT:40px>
<span style="FONT-FAMILY:Courier New"></span>
</div>
<br>
<h2>
Setting Environment Variables
</h2>
The NDK requires that you set two environment variables:<br>
<ul>
<li>
PREBUILT must be set to the directory that contains the prebuilt
toolchain. Include the "prebuilt" directory in the path. Example:
/Volumes/android/prebuilt<br>
</li>
<li>
ANDROID_SDK_BASE must be set to the directory that contains the
Android SDK. Example: ~/AndroidSDK<br>
</li>
</ul>
<br>
<h2>
<span style=FONT-FAMILY:Verdana>Unpacking the NDK</span>
</h2>
Unpack the android_ndk.tar.gz into your working directory<br>
<br>
<div style=MARGIN-LEFT:40px>
<span style="FONT-FAMILY:Courier New">tar -zxvf
android_ndk.tar.gz</span><br>
</div>
<br>
This will create a directory called ndk. It should contain a README.html
file (this file) and the following directories: config, include, lib, and
sample.<br>
<br>
Look in the "samples" directory for samples showing how to use the NDK.<br>
<br>
<br>
</div>
<br>
</div>
<br>
</div>
<br></body>
</html>

View File

@@ -100,7 +100,7 @@ ndk_src_dest_dir := $(ndk_src_tree)/ndk
bionic_src_dest_dir := $(ndk_src_dest_dir)/include/bionic bionic_src_dest_dir := $(ndk_src_dest_dir)/include/bionic
# Destinations of all common files (not picked up by tree rules below) # Destinations of all common files (not picked up by tree rules below)
ndk_common_dest_files := $(ndk_common_dest_dir)/README \ ndk_common_dest_files := $(ndk_common_dest_dir)/Android_NDK_README.html \
$(ndk_common_dest_dir)/config/armelf.x \ $(ndk_common_dest_dir)/config/armelf.x \
$(ndk_common_dest_dir)/config/armelflib.x \ $(ndk_common_dest_dir)/config/armelflib.x \
$(ndk_common_dest_dir)/lib/crtbegin_dynamic.o \ $(ndk_common_dest_dir)/lib/crtbegin_dynamic.o \
@@ -114,8 +114,8 @@ ndk_common_full_dest_files := \
$(ndk_common_full_dest_dir)/lib/libstdc++.so $(ndk_common_full_dest_dir)/lib/libstdc++.so
# Install common files outside common trees # Install common files outside common trees
$(ndk_common_dest_dir)/README: $(LOCAL_PATH)/README | $(ACP) $(ndk_common_dest_dir)/Android_NDK_README.html: $(LOCAL_PATH)/Android_NDK_README.html | $(ACP)
@echo "NDK README: from $? to $@" @echo "NDK Android_NDK_README.html: from $? to $@"
$(copy-file-to-target) $(copy-file-to-target)
$(ndk_common_dest_dir)/config/armelf.x: $(BUILD_SYSTEM)/armelf.x | $(ACP) $(ndk_common_dest_dir)/config/armelf.x: $(BUILD_SYSTEM)/armelf.x | $(ACP)

View File

@@ -1,30 +0,0 @@
Using the Native Development Kit (NDK)
version 1.2
PRECONDITIONS
The Native Development Kit may be installed on either Linux or OS X.
The NDK must be installed on a case-sensitive file system. Linux
file systems are always case-sensitive, but the default OS X file
system is case-insenstive. A case-sensitive file sytem can be
created either by partitioning your drive to include a case-sensitive
partition or by creating a disk image that is case-sensitive.
STEP 1
Installing arm-eabi-gcc
-----------------------
1) Untar the android_ndk.tar.gz:
tar -zxvf android_ndk.tar.gz
This will create a directory called ndk. It should include a README file (this
file) and the following directories: config, include, lib, sample and toolchain.
STEP 2
Samples
-------
Look in the "samples" directory for samples of how to use the NDK.

View File

@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := samples development LOCAL_MODULE_TAGS := samples
# Only compile source java files in this apk. # Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SRC_FILES := $(call all-java-files-under, src)

View File

@@ -152,6 +152,18 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".app.ReorderOnLaunch"
android:label="@string/activity_reorder">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".app.ReorderTwo" />
<activity android:name=".app.ReorderThree" />
<activity android:name=".app.ReorderFour" />
<!-- Intent Samples --> <!-- Intent Samples -->
<activity android:name=".app.Intents" android:label="@string/activity_intents"> <activity android:name=".app.Intents" android:label="@string/activity_intents">
@@ -1640,6 +1652,25 @@
</intent-filter> </intent-filter>
</activity> </activity>
<!-- ************************************* -->
<!-- APPWIDGET PACKAGE SAMPLES -->
<!-- ************************************* -->
<receiver android:name=".appwidget.ExampleAppWidgetProvider">
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/appwidget_provider" />
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
</receiver>
<receiver android:name=".appwidget.ExampleBroadcastReceiver" android:enabled="false">
<intent-filter>
<action android:name="android.intent.ACTION_TIMEZONE_CHANGED" />
<action android:name="android.intent.ACTION_TIME" />
</intent-filter>
</receiver>
<!-- ************************************* --> <!-- ************************************* -->
<!-- OTHER SAMPLES --> <!-- OTHER SAMPLES -->
<!-- ************************************* --> <!-- ************************************* -->

View File

@@ -2,18 +2,18 @@
</p> </p>
<dl> <dl>
<dt><a href="src/com/example/android/apis/app/">App</a></dt> <dt><a href="src/com/example/android/apis/app/index.html">App</a></dt>
<dd></dd> <dd></dd>
<dt><a href="src/com/example/android/apis/content/">Content</a></dt> <dt><a href="src/com/example/android/apis/content/index.html">Content</a></dt>
<dd></dd> <dd></dd>
<dt><a href="src/com/example/android/apis/view/">View</a></dt> <dt><a href="src/com/example/android/apis/view/index.html">View</a></dt>
<dd></dd> <dd></dd>
<dt><a href="src/com/example/android/apis/graphics/">Graphics</a></dt> <dt><a href="src/com/example/android/apis/graphics/index.html">Graphics</a></dt>
<dd></dd> <dd></dd>
<dt><a href="src/com/example/android/apis/text/">Text</a></dt> <dt><a href="src/com/example/android/apis/text/index.html">Text</a></dt>
<dd></dd> <dd></dd>
</dl> </dl>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2006 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/appwidget_configure_instructions"
/>
<EditText
android:id="@+id/appwidget_prefix"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/save_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/ok"
/>
</LinearLayout>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2006 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.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/appwidget_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ff000000"
/>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<!-- Demonstrates using Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
See corresponding Java code com.example.android.apis.app.ReorderOnLaunch.java. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_weight="0"
android:paddingBottom="4dip"
android:text="@string/reorder_four_text"/>
<Button android:id="@+id/reorder_second_to_front"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/reorder_second_to_front">
</Button>
</LinearLayout>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<!-- Demonstrates using Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
See corresponding Java code com.android.sdk.app.ReorderOnLaunch.java. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_weight="0"
android:paddingBottom="4dip"
android:text="@string/reorder_on_launch"/>
<Button android:id="@+id/reorder_launch_two"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/reorder_launch_two">
</Button>
</LinearLayout>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<!-- Demonstrates using Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
See corresponding Java code com.example.android.apis.app.ReorderOnLaunch.java. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_weight="0"
android:paddingBottom="4dip"
android:text="@string/reorder_three_text"/>
<Button android:id="@+id/reorder_launch_four"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/reorder_launch_four">
</Button>
</LinearLayout>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<!-- Demonstrates using Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
See corresponding Java code com.example.android.apis.app.ReorderOnLaunch.java. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_weight="0"
android:paddingBottom="4dip"
android:text="@string/reorder_two_text"/>
<Button android:id="@+id/reorder_launch_three"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/reorder_launch_three">
</Button>
</LinearLayout>

View File

@@ -185,6 +185,16 @@
<string name="custom_title_left_button">Change Left</string> <string name="custom_title_left_button">Change Left</string>
<string name="custom_title_right_button">Change Right</string> <string name="custom_title_right_button">Change Right</string>
<string name="activity_reorder">App/Activity/Reorder Activities</string>
<string name="reorder_on_launch">This is the first of a sequence of four Activities. A button on the fourth will use the Intent.FLAG_ACTIVITY_REORDER_TO_FRONT flag to bring the second of the activities to the front of the history stack. After that, proceeding back through the history should begin with the newly-frontmost second reorder activity, then the fourth, the third, and finally the first.</string>
<string name="reorder_launch_two">Go to the second</string>
<string name="reorder_two_text">This is the second in a sequence of four Activities.</string>
<string name="reorder_launch_three">Go to the third</string>
<string name="reorder_three_text">This is the third of a sequence of four Activities.</string>
<string name="reorder_launch_four">Go to the fourth</string>
<string name="reorder_four_text">This is the last in a sequence of four Activities.</string>
<string name="reorder_second_to_front">Bring the second in front</string>
<string name="menu_from_xml_title">App/Menu/Inflate from XML</string> <string name="menu_from_xml_title">App/Menu/Inflate from XML</string>
<string name="menu_from_xml_instructions_press_menu">Select a menu resource and press the menu key.</string> <string name="menu_from_xml_instructions_press_menu">Select a menu resource and press the menu key.</string>
<string name="menu_from_xml_instructions_go_back">If you want to choose another menu resource, go back and re-run this activity.</string> <string name="menu_from_xml_instructions_go_back">If you want to choose another menu resource, go back and re-run this activity.</string>
@@ -803,5 +813,12 @@
<string name="textColorTertiary">textColorTertiary</string> <string name="textColorTertiary">textColorTertiary</string>
<string name="listSeparatorTextViewStyle">listSeparatorTextViewStyle</string> <string name="listSeparatorTextViewStyle">listSeparatorTextViewStyle</string>
<!-- ============================ -->
<!-- AppWidget examples strings -->
<!-- ============================ -->
<string name="appwidget_configure_instructions">This text will be shown before the date in our example widget.</string>
<string name="appwidget_prefix_default">Oh hai</string>
<string name="appwidget_text_format"><xliff:g id="prefix">%1$s</xliff:g>: <xliff:g id="time">%2$s</xliff:g></string>
</resources> </resources>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2006 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.
-->
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="60dp"
android:minHeight="30dp"
android:updatePeriodMillis="86400000"
android:initialLayout="@layout/appwidget_provider"
android:configure="com.example.android.apis.appwidget.ExampleAppWidgetConfigure"
>
</appwidget-provider>
<!-- 86400000 is the value of AlarmManager.INTERVAL_DAY - or once per day. -->

View File

@@ -22,6 +22,10 @@
android:hint="@string/search_hint" android:hint="@string/search_hint"
android:searchMode="showSearchLabelAsBadge" android:searchMode="showSearchLabelAsBadge"
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"
android:voiceLanguageModel="free_form"
android:voicePromptText="@string/search_invoke"
android:searchSuggestAuthority="com.example.android.apis.SuggestionProvider" android:searchSuggestAuthority="com.example.android.apis.SuggestionProvider"
android:searchSuggestSelection=" ? " android:searchSuggestSelection=" ? "
/> />

View File

@@ -0,0 +1,46 @@
/*
* 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.apis.app;
import com.example.android.apis.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ReorderFour extends Activity {
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.reorder_four);
Button twoButton = (Button) findViewById(R.id.reorder_second_to_front);
twoButton.setOnClickListener(mClickListener);
}
private final OnClickListener mClickListener = new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(ReorderFour.this, ReorderTwo.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}
};
}

View File

@@ -0,0 +1,44 @@
/*
* 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.apis.app;
import com.example.android.apis.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ReorderOnLaunch extends Activity {
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.reorder_on_launch);
Button twoButton = (Button) findViewById(R.id.reorder_launch_two);
twoButton.setOnClickListener(mClickListener);
}
private final OnClickListener mClickListener = new OnClickListener() {
public void onClick(View v) {
startActivity(new Intent(ReorderOnLaunch.this, ReorderTwo.class));
}
};
}

View File

@@ -0,0 +1,44 @@
/*
* 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.apis.app;
import com.example.android.apis.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ReorderThree extends Activity {
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.reorder_three);
Button twoButton = (Button) findViewById(R.id.reorder_launch_four);
twoButton.setOnClickListener(mClickListener);
}
private final OnClickListener mClickListener = new OnClickListener() {
public void onClick(View v) {
startActivity(new Intent(ReorderThree.this, ReorderFour.class));
}
};
}

View File

@@ -0,0 +1,44 @@
/*
* 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.apis.app;
import com.example.android.apis.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ReorderTwo extends Activity {
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.reorder_two);
Button twoButton = (Button) findViewById(R.id.reorder_launch_three);
twoButton.setOnClickListener(mClickListener);
}
private final OnClickListener mClickListener = new OnClickListener() {
public void onClick(View v) {
startActivity(new Intent(ReorderTwo.this, ReorderThree.class));
}
};
}

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.samples.app; package com.example.android.apis.app;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;

View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) 2008 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.apis.appwidget;
import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import java.util.ArrayList;
// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import com.example.android.apis.R;
/**
* The configuration screen for the ExampleAppWidgetProvider widget sample.
*/
public class ExampleAppWidgetConfigure extends Activity {
static final String TAG = "ExampleAppWidgetConfigure";
private static final String PREFS_NAME
= "com.example.android.apis.appwidget.ExampleAppWidgetProvider";
private static final String PREF_PREFIX_KEY = "prefix_";
int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
EditText mAppWidgetPrefix;
public ExampleAppWidgetConfigure() {
super();
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Set the result to CANCELED. This will cause the widget host to cancel
// out of the widget placement if they press the back button.
setResult(RESULT_CANCELED);
// Set the view layout resource to use.
setContentView(R.layout.appwidget_configure);
// Find the EditText
mAppWidgetPrefix = (EditText)findViewById(R.id.appwidget_prefix);
// Bind the action for the save button.
findViewById(R.id.save_button).setOnClickListener(mOnClickListener);
// Find the widget id from the intent.
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
}
// If they gave us an intent without the widget id, just bail.
if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
}
mAppWidgetPrefix.setText(loadTitlePref(ExampleAppWidgetConfigure.this, mAppWidgetId));
}
View.OnClickListener mOnClickListener = new View.OnClickListener() {
public void onClick(View v) {
// When the button is clicked, save the string in our prefs and return that they
// clicked OK.
saveTitlePref(ExampleAppWidgetConfigure.this, mAppWidgetId,
mAppWidgetPrefix.getText().toString());
setResult(RESULT_OK);
finish();
}
};
// Write the prefix to the SharedPreferences object for this widget
static void saveTitlePref(Context context, int appWidgetId, String text) {
SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
prefs.putString(PREF_PREFIX_KEY + appWidgetId, text);
prefs.commit();
}
// Read the prefix from the SharedPreferences object for this widget.
// If there is no preference saved, get the default from a resource
static String loadTitlePref(Context context, int appWidgetId) {
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
String prefix = prefs.getString(PREF_PREFIX_KEY, null);
if (prefix != null) {
return prefix;
} else {
return context.getString(R.string.appwidget_prefix_default);
}
}
static void deleteTitlePref(Context context, int appWidgetId) {
}
static void loadAllTitlePrefs(Context context, ArrayList<Integer> appWidgetIds,
ArrayList<String> texts) {
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2008 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.apis.appwidget;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.SystemClock;
import android.util.Log;
import android.widget.RemoteViews;
import java.util.ArrayList;
// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import com.example.android.apis.R;
/**
* A widget provider. We have a string that we pull from a preference in order to show
* the configuration settings and the current time when the widget was updated. We also
* register a BroadcastReceiver for time-changed and timezone-changed broadcasts, and
* update then too.
*
* <p>See also the following files:
* <ul>
* <li>ExampleAppWidgetConfigure.java</li>
* <li>ExampleBroadcastReceiver.java</li>
* <li>res/layout/appwidget_configure.xml</li>
* <li>res/layout/appwidget_provider.xml</li>
* <li>res/xml/appwidget_provider.xml</li>
* </ul>
*/
public class ExampleAppWidgetProvider extends AppWidgetProvider {
// log tag
private static final String TAG = "ExampleAppWidgetProvider";
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
Log.d(TAG, "onUpdate");
// For each widget that needs an update, get the text that we should display:
// - Create a RemoteViews object for it
// - Set the text in the RemoteViews object
// - Tell the AppWidgetManager to show that views object for the widget.
final int N = appWidgetIds.length;
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
String titlePrefix = ExampleAppWidgetConfigure.loadTitlePref(context, appWidgetId);
updateAppWidget(context, appWidgetManager, appWidgetId, titlePrefix);
}
}
public void onDeleted(Context context, int[] appWidgetIds) {
Log.d(TAG, "onDeleted");
// When the user deletes the widget, delete the preference associated with it.
final int N = appWidgetIds.length;
for (int i=0; i<N; i++) {
ExampleAppWidgetConfigure.deleteTitlePref(context, appWidgetIds[i]);
}
}
public void onEnabled(Context context) {
Log.d(TAG, "onEnabled");
// When the first widget is created, register for the TIMEZONE_CHANGED and TIME_CHANGED
// broadcasts. We don't want to be listening for these if nobody has our widget active.
// This setting is sticky across reboots, but that doesn't matter, because this will
// be called after boot if there is a widget instance for this provider.
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(
new ComponentName("com.example.android.apis", ".appwidget.ExampleBroadcastReceiver"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
public void onDisabled(Context context) {
// When the first widget is created, stop listening for the TIMEZONE_CHANGED and
// TIME_CHANGED broadcasts.
Log.d(TAG, "onDisabled");
Class clazz = ExampleBroadcastReceiver.class;
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(
new ComponentName("com.example.android.apis", ".appwidget.ExampleBroadcastReceiver"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId, String titlePrefix) {
Log.d(TAG, "updateAppWidget appWidgetId=" + appWidgetId + " titlePrefix=" + titlePrefix);
// Getting the string this way allows the string to be localized. The format
// string is filled in using java.util.Formatter-style format strings.
CharSequence text = context.getString(R.string.appwidget_text_format,
ExampleAppWidgetConfigure.loadTitlePref(context, appWidgetId),
"0x" + Long.toHexString(SystemClock.elapsedRealtime()));
// Construct the RemoteViews object. It takes the package name (in our case, it's our
// package, but it needs this because on the other side it's the widget host inflating
// the layout from our package).
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider);
views.setTextViewText(R.id.appwidget_text, text);
// Tell the widget manager
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2008 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.apis.appwidget;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.util.Log;
import android.widget.RemoteViews;
import java.util.ArrayList;
// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import com.example.android.apis.R;
/**
* A BroadcastReceiver that listens for updates for the ExampleAppWidgetProvider. This
* BroadcastReceiver starts off disabled, and we only enable it when there is a widget
* instance created, in order to only receive notifications when we need them.
*/
public class ExampleBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Log.d("ExmampleBroadcastReceiver", "intent=" + intent);
// For our example, we'll also update all of the widgets when the timezone
// changes, or the user or network sets the time.
String action = intent.getAction();
if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)
|| action.equals(Intent.ACTION_TIME_CHANGED)) {
AppWidgetManager gm = AppWidgetManager.getInstance(context);
ArrayList<Integer> appWidgetIds = new ArrayList();
ArrayList<String> texts = new ArrayList();
ExampleAppWidgetConfigure.loadAllTitlePrefs(context, appWidgetIds, texts);
final int N = appWidgetIds.size();
for (int i=0; i<N; i++) {
ExampleAppWidgetProvider.updateAppWidget(context, gm, appWidgetIds.get(i), texts.get(i));
}
}
}
}

View File

@@ -24,6 +24,7 @@ import android.graphics.drawable.Drawable;
public class ProxyDrawable extends Drawable { public class ProxyDrawable extends Drawable {
private Drawable mProxy; private Drawable mProxy;
private boolean mMutated;
public ProxyDrawable(Drawable target) { public ProxyDrawable(Drawable target) {
mProxy = target; mProxy = target;
@@ -88,5 +89,14 @@ public class ProxyDrawable extends Drawable {
mProxy.setAlpha(alpha); mProxy.setAlpha(alpha);
} }
} }
@Override
public Drawable mutate() {
if (mProxy != null && !mMutated && super.mutate() == this) {
mProxy.mutate();
mMutated = true;
}
return this;
}
} }

View File

@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := eng LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_SRC_FILES := $(call all-subdir-java-files)

View File

@@ -223,14 +223,18 @@ class GTView extends SurfaceView implements SurfaceHolder.Callback {
private float mMotionStartTiltAngle; private float mMotionStartTiltAngle;
private int mMotionDirection; private int mMotionDirection;
private boolean mPaused = true;
private boolean mHaveSurface = false;
private boolean mStartAnimating = false;
public void surfaceCreated(SurfaceHolder holder) { public void surfaceCreated(SurfaceHolder holder) {
EGL10 egl = (EGL10)EGLContext.getEGL(); mHaveSurface = true;
mEGLSurface = egl.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, this, null); startEGL();
egl.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
} }
public void surfaceDestroyed(SurfaceHolder holder) { public void surfaceDestroyed(SurfaceHolder holder) {
// nothing to do mHaveSurface = false;
stopEGL();
} }
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
@@ -249,10 +253,26 @@ class GTView extends SurfaceView implements SurfaceHolder.Callback {
getHolder().addCallback(this); getHolder().addCallback(this);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU); getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
AssetManager am = context.getAssets();
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
mClock = new Clock();
startEGL();
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
}
/**
* Creates an egl context. If the state of the activity is right, also
* creates the egl surface. Otherwise the surface will be created in a
* future call to createEGLSurface().
*/
private void startEGL() {
EGL10 egl = (EGL10)EGLContext.getEGL(); EGL10 egl = (EGL10)EGLContext.getEGL();
if (mEGLContext == null) {
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
int[] version = new int[2]; int[] version = new int[2];
egl.eglInitialize(dpy, version); egl.eglInitialize(dpy, version);
@@ -264,15 +284,12 @@ class GTView extends SurfaceView implements SurfaceHolder.Callback {
int[] num_config = new int[1]; int[] num_config = new int[1];
egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config); egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config);
mEGLConfig = configs[0]; mEGLConfig = configs[0];
mEGLContext = egl.eglCreateContext(dpy, mEGLConfig, EGL10.EGL_NO_CONTEXT, null);
mEGLContext = egl.eglCreateContext(dpy, mEGLConfig,
EGL10.EGL_NO_CONTEXT, null);
mEGLDisplay = dpy; mEGLDisplay = dpy;
mClock = new Clock(); AssetManager am = mContext.getAssets();
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
try { try {
loadAssets(am); loadAssets(am);
} catch (IOException ioe) { } catch (IOException ioe) {
@@ -284,25 +301,67 @@ class GTView extends SurfaceView implements SurfaceHolder.Callback {
} }
} }
if (mEGLSurface == null && !mPaused && mHaveSurface) {
mEGLSurface = egl.eglCreateWindowSurface(mEGLDisplay, mEGLConfig,
this, null);
egl.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface,
mEGLContext);
mInitialized = false;
if (mStartAnimating) {
startAnimating();
mStartAnimating = false;
}
}
}
/** /**
* Destroy the view. * Destroys the egl context. If an egl surface has been created, it is
* destroyed as well.
*/ */
public void destroy() { private void stopEGL() {
EGL10 egl = (EGL10)EGLContext.getEGL(); EGL10 egl = (EGL10)EGLContext.getEGL();
if (mEGLSurface != null) {
egl.eglMakeCurrent(mEGLDisplay, egl.eglMakeCurrent(mEGLDisplay,
egl.EGL_NO_SURFACE, egl.EGL_NO_SURFACE, egl.EGL_NO_CONTEXT); egl.EGL_NO_SURFACE, egl.EGL_NO_SURFACE, egl.EGL_NO_CONTEXT);
egl.eglDestroyContext(mEGLDisplay, mEGLContext);
egl.eglDestroySurface(mEGLDisplay, mEGLSurface); egl.eglDestroySurface(mEGLDisplay, mEGLSurface);
mEGLSurface = null;
}
if (mEGLContext != null) {
egl.eglDestroyContext(mEGLDisplay, mEGLContext);
egl.eglTerminate(mEGLDisplay); egl.eglTerminate(mEGLDisplay);
mEGLContext = null; mEGLContext = null;
mEGLDisplay = null;
mEGLConfig = null;
}
}
public void onPause() {
mPaused = true;
stopAnimating();
stopEGL();
}
public void onResume() {
mPaused = false;
startEGL();
}
public void destroy() {
stopAnimating();
stopEGL();
} }
/** /**
* Begin animation. * Begin animation.
*/ */
public void startAnimating() { public void startAnimating() {
if (mEGLSurface == null) {
mStartAnimating = true; // will start when egl surface is created
} else {
mHandler.sendEmptyMessage(INVALIDATE); mHandler.sendEmptyMessage(INVALIDATE);
} }
}
/** /**
* Quit animation. * Quit animation.
@@ -1390,32 +1449,25 @@ public class GlobalTime extends Activity {
GTView gtView = null; GTView gtView = null;
private void setGTView() {
if (gtView == null) {
gtView = new GTView(this);
setContentView(gtView);
}
}
@Override protected void onCreate(Bundle icicle) { @Override protected void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
setGTView(); gtView = new GTView(this);
setContentView(gtView);
} }
@Override protected void onResume() { @Override protected void onResume() {
super.onResume(); super.onResume();
setGTView(); gtView.onResume();
Looper.myQueue().addIdleHandler(new Idler()); Looper.myQueue().addIdleHandler(new Idler());
} }
@Override protected void onPause() { @Override protected void onPause() {
super.onPause(); super.onPause();
gtView.stopAnimating(); gtView.onPause();
} }
@Override protected void onStop() { @Override protected void onStop() {
super.onStop(); super.onStop();
gtView.stopAnimating();
gtView.destroy(); gtView.destroy();
gtView = null; gtView = null;
} }

View File

@@ -105,7 +105,7 @@ public class ApplicationsStackLayout extends ViewGroup implements View.OnClickLi
a.recycle(); a.recycle();
mIconSize = (int) getResources().getDimension(android.R.dimen.app_icon_size); mIconSize = 42; //(int) getResources().getDimension(android.R.dimen.app_icon_size);
initLayout(); initLayout();
} }

View File

@@ -21,28 +21,26 @@ import android.app.ActivityManager;
import android.app.SearchManager; import android.app.SearchManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter; import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.ColorFilter;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable; import android.graphics.drawable.PaintDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Environment;
import android.util.Log; import android.util.Log;
import android.util.Xml;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@@ -57,14 +55,19 @@ import android.widget.ArrayAdapter;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.GridView; import android.widget.GridView;
import android.widget.TextView; import android.widget.TextView;
import android.net.Uri;
import java.io.IOException; import java.io.IOException;
import java.io.FileReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
public class Home extends Activity { public class Home extends Activity {
/** /**
* Tag used for logging errors. * Tag used for logging errors.
@@ -76,6 +79,13 @@ public class Home extends Activity {
*/ */
private static final String KEY_SAVE_GRID_OPENED = "grid.opened"; private static final String KEY_SAVE_GRID_OPENED = "grid.opened";
private static final String DEFAULT_FAVORITES_PATH = "etc/favorites.xml";
private static final String TAG_FAVORITES = "favorites";
private static final String TAG_FAVORITE = "favorite";
private static final String TAG_PACKAGE = "package";
private static final String TAG_CLASS = "class";
// Identifiers for option menu items // Identifiers for option menu items
private static final int MENU_WALLPAPER_SETTINGS = Menu.FIRST + 1; private static final int MENU_WALLPAPER_SETTINGS = Menu.FIRST + 1;
private static final int MENU_SEARCH = MENU_WALLPAPER_SETTINGS + 1; private static final int MENU_SEARCH = MENU_WALLPAPER_SETTINGS + 1;
@@ -90,11 +100,8 @@ public class Home extends Activity {
private static ArrayList<ApplicationInfo> mApplications; private static ArrayList<ApplicationInfo> mApplications;
private static LinkedList<ApplicationInfo> mFavorites; private static LinkedList<ApplicationInfo> mFavorites;
private Handler mHandler = new Handler();
private final BroadcastReceiver mWallpaperReceiver = new WallpaperIntentReceiver(); private final BroadcastReceiver mWallpaperReceiver = new WallpaperIntentReceiver();
private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver(); private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver();
private final ContentObserver mObserver = new FavoritesChangeObserver();
private GridView mGrid; private GridView mGrid;
@@ -120,7 +127,6 @@ public class Home extends Activity {
setContentView(R.layout.home); setContentView(R.layout.home);
registerIntentReceivers(); registerIntentReceivers();
registerContentObservers();
setDefaultWallpaper(); setDefaultWallpaper();
@@ -156,7 +162,6 @@ public class Home extends Activity {
mApplications.get(i).icon.setCallback(null); mApplications.get(i).icon.setCallback(null);
} }
getContentResolver().unregisterContentObserver(mObserver);
unregisterReceiver(mWallpaperReceiver); unregisterReceiver(mWallpaperReceiver);
unregisterReceiver(mApplicationsReceiver); unregisterReceiver(mApplicationsReceiver);
} }
@@ -198,16 +203,6 @@ public class Home extends Activity {
registerReceiver(mApplicationsReceiver, filter); registerReceiver(mApplicationsReceiver, filter);
} }
/**
* Registers various content observers. The current implementation registers
* only a favorites observer to keep track of the favorites applications.
*/
private void registerContentObservers() {
ContentResolver resolver = getContentResolver();
resolver.registerContentObserver(Uri.parse("content://" +
android.provider.Settings.AUTHORITY + "/favorites?notify=true"), true, mObserver);
}
/** /**
* Creates a new appplications adapter for the grid view and registers it. * Creates a new appplications adapter for the grid view and registers it.
*/ */
@@ -247,7 +242,7 @@ public class Home extends Activity {
Log.e(LOG_TAG, "Failed to clear wallpaper " + e); Log.e(LOG_TAG, "Failed to clear wallpaper " + e);
} }
} else { } else {
getWindow().setBackgroundDrawable(wallpaper); getWindow().setBackgroundDrawable(new ClippedDrawable(wallpaper));
} }
mWallpaperChecked = true; mWallpaperChecked = true;
} }
@@ -259,18 +254,17 @@ public class Home extends Activity {
*/ */
private void bindFavorites(boolean isLaunching) { private void bindFavorites(boolean isLaunching) {
if (!isLaunching || mFavorites == null) { if (!isLaunching || mFavorites == null) {
final Cursor c = getContentResolver().query(Uri.parse("content://" +
android.provider.Settings.AUTHORITY + "/favorites?notify=true"),
null, null, null, "cellX");
final int intentIndex = c.getColumnIndexOrThrow("intent"); FileReader favReader;
final int titleIndex = c.getColumnIndexOrThrow("title");
final int typeIndex = c.getColumnIndexOrThrow("itemType");
final PackageManager manager = getPackageManager(); // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
final File favFile = new File(Environment.getRootDirectory(), DEFAULT_FAVORITES_PATH);
ApplicationInfo info; try {
String intentDescription; favReader = new FileReader(favFile);
} catch (FileNotFoundException e) {
Log.e(LOG_TAG, "Couldn't find or open favorites file " + favFile);
return;
}
if (mFavorites == null) { if (mFavorites == null) {
mFavorites = new LinkedList<ApplicationInfo>(); mFavorites = new LinkedList<ApplicationInfo>();
@@ -278,38 +272,77 @@ public class Home extends Activity {
mFavorites.clear(); mFavorites.clear();
} }
while (c.moveToNext()) { final Intent intent = new Intent(Intent.ACTION_MAIN, null);
final int itemType = c.getInt(typeIndex); intent.addCategory(Intent.CATEGORY_LAUNCHER);
if (itemType == 0 || // 0 == application final PackageManager packageManager = getPackageManager();
itemType == 1) { // 1 == shortcut
intentDescription = c.getString(intentIndex);
if (intentDescription == null) {
continue;
}
Intent intent;
try { try {
intent = Intent.getIntent(intentDescription); final XmlPullParser parser = Xml.newPullParser();
} catch (java.net.URISyntaxException e) { parser.setInput(favReader);
continue;
beginDocument(parser, TAG_FAVORITES);
ApplicationInfo info;
while (true) {
nextElement(parser);
String name = parser.getName();
if (!TAG_FAVORITE.equals(name)) {
break;
} }
info = getApplicationInfo(manager, intent);
final String favoritePackage = parser.getAttributeValue(null, TAG_PACKAGE);
final String favoriteClass = parser.getAttributeValue(null, TAG_CLASS);
final ComponentName cn = new ComponentName(favoritePackage, favoriteClass);
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
info = getApplicationInfo(packageManager, intent);
if (info != null) { if (info != null) {
info.title = c.getString(titleIndex);
info.intent = intent; info.intent = intent;
mFavorites.addFirst(info); mFavorites.addFirst(info);
} }
} }
} catch (XmlPullParserException e) {
Log.w(LOG_TAG, "Got exception parsing favorites.", e);
} catch (IOException e) {
Log.w(LOG_TAG, "Got exception parsing favorites.", e);
} }
c.close();
} }
mApplicationsStack.setFavorites(mFavorites); mApplicationsStack.setFavorites(mFavorites);
} }
private static void beginDocument(XmlPullParser parser, String firstElementName)
throws XmlPullParserException, IOException {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}
if (!parser.getName().equals(firstElementName)) {
throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
", expected " + firstElementName);
}
}
private static void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
}
/** /**
* Refreshes the recently launched applications stacked over the favorites. The number * Refreshes the recently launched applications stacked over the favorites. The number
* of recents depends on how many favorites are present. * of recents depends on how many favorites are present.
@@ -361,14 +394,6 @@ public class Home extends Activity {
return info; return info;
} }
/**
* When the notification that favorites have changed is received, requests
* a favorites list refresh.
*/
private void onFavoritesChanged() {
bindFavorites(false);
}
@Override @Override
public boolean dispatchKeyEvent(KeyEvent event) { public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) { if (event.getAction() == KeyEvent.ACTION_DOWN) {
@@ -530,7 +555,7 @@ public class Home extends Activity {
private class WallpaperIntentReceiver extends BroadcastReceiver { private class WallpaperIntentReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
getWindow().setBackgroundDrawable(getWallpaper()); getWindow().setBackgroundDrawable(new ClippedDrawable(getWallpaper()));
} }
} }
@@ -547,20 +572,6 @@ public class Home extends Activity {
} }
} }
/**
* Receives notifications whenever the user favorites have changed.
*/
private class FavoritesChangeObserver extends ContentObserver {
public FavoritesChangeObserver() {
super(mHandler);
}
@Override
public void onChange(boolean selfChange) {
onFavoritesChanged();
}
}
/** /**
* GridView adapter to show the list of all installed applications. * GridView adapter to show the list of all installed applications.
*/ */
@@ -580,13 +591,12 @@ public class Home extends Activity {
convertView = inflater.inflate(R.layout.application, parent, false); convertView = inflater.inflate(R.layout.application, parent, false);
} }
//final ImageView imageView = (ImageView) convertView.findViewById(R.id.icon);
Drawable icon = info.icon; Drawable icon = info.icon;
if (!info.filtered) { if (!info.filtered) {
final Resources resources = getContext().getResources(); //final Resources resources = getContext().getResources();
int width = (int) resources.getDimension(android.R.dimen.app_icon_size); int width = 42;//(int) resources.getDimension(android.R.dimen.app_icon_size);
int height = (int) resources.getDimension(android.R.dimen.app_icon_size); int height = 42;//(int) resources.getDimension(android.R.dimen.app_icon_size);
final int iconWidth = icon.getIntrinsicWidth(); final int iconWidth = icon.getIntrinsicWidth();
final int iconHeight = icon.getIntrinsicHeight(); final int iconHeight = icon.getIntrinsicHeight();
@@ -687,4 +697,47 @@ public class Home extends Activity {
startActivity(app.intent); startActivity(app.intent);
} }
} }
/**
* When a drawable is attached to a View, the View gives the Drawable its dimensions
* by calling Drawable.setBounds(). In this application, the View that draws the
* wallpaper has the same size as the screen. However, the wallpaper might be larger
* that the screen which means it will be automatically stretched. Because stretching
* a bitmap while drawing it is very expensive, we use a ClippedDrawable instead.
* This drawable simply draws another wallpaper but makes sure it is not stretched
* by always giving it its intrinsic dimensions. If the wallpaper is larger than the
* screen, it will simply get clipped but it won't impact performance.
*/
private class ClippedDrawable extends Drawable {
private final Drawable mWallpaper;
public ClippedDrawable(Drawable wallpaper) {
mWallpaper = wallpaper;
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
// Ensure the wallpaper is as large as it really is, to avoid stretching it
// at drawing time
mWallpaper.setBounds(left, top, left + mWallpaper.getIntrinsicWidth(),
top + mWallpaper.getIntrinsicHeight());
}
public void draw(Canvas canvas) {
mWallpaper.draw(canvas);
}
public void setAlpha(int alpha) {
mWallpaper.setAlpha(alpha);
}
public void setColorFilter(ColorFilter cf) {
mWallpaper.setColorFilter(cf);
}
public int getOpacity() {
return mWallpaper.getOpacity();
}
}
} }

View File

@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := eng samples LOCAL_MODULE_TAGS := samples
# Only compile source java files in this apk. # Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SRC_FILES := $(call all-java-files-under, src)

View File

@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := eng samples LOCAL_MODULE_TAGS := samples
# Only compile source java files in this apk. # Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SRC_FILES := $(call all-java-files-under, src)

View File

@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := eng samples LOCAL_MODULE_TAGS := samples
LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_SRC_FILES := $(call all-subdir-java-files)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -19,5 +19,5 @@
--> -->
<resources> <resources>
<dimen name="key_height">46px</dimen> <dimen name="key_height">46dip</dimen>
</resources> </resources>

View File

@@ -19,7 +19,7 @@
--> -->
<resources> <resources>
<dimen name="key_height">50px</dimen> <dimen name="key_height">50dip</dimen>
<dimen name="candidate_font_height">16sp</dimen> <dimen name="candidate_font_height">16sp</dimen>
<dimen name="candidate_vertical_padding">6sp</dimen> <dimen name="candidate_vertical_padding">6sp</dimen>
</resources> </resources>

View File

@@ -25,9 +25,7 @@
<string name="word_separators">\u0020.,;:!?\n()[]*&amp;@{}/&lt;&gt;_+=|&quot;</string> <string name="word_separators">\u0020.,;:!?\n()[]*&amp;@{}/&lt;&gt;_+=|&quot;</string>
<!-- Labels on soft keys --> <!-- Labels on soft keys -->
<string name="label_done">Done</string> <string name="label_go_key">Go</string>
<string name="label_search">Search</string> <string name="label_next_key">Next</string>
<string name="label_enter">Enter</string> <string name="label_send_key">Send</string>
<string name="label_next">Next</string>
<string name="label_previous">Previous</string>
</resources> </resources>

View File

@@ -20,9 +20,14 @@ import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.XmlResourceParser; import android.content.res.XmlResourceParser;
import android.inputmethodservice.Keyboard; import android.inputmethodservice.Keyboard;
import android.inputmethodservice.Keyboard.Key;
import android.inputmethodservice.Keyboard.Row;
import android.view.inputmethod.EditorInfo;
public class LatinKeyboard extends Keyboard { public class LatinKeyboard extends Keyboard {
private Key mEnterKey;
public LatinKeyboard(Context context, int xmlLayoutResId) { public LatinKeyboard(Context context, int xmlLayoutResId) {
super(context, xmlLayoutResId); super(context, xmlLayoutResId);
} }
@@ -35,7 +40,49 @@ public class LatinKeyboard extends Keyboard {
@Override @Override
protected Key createKeyFromXml(Resources res, Row parent, int x, int y, protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
XmlResourceParser parser) { XmlResourceParser parser) {
return new LatinKey(res, parent, x, y, parser); Key key = new LatinKey(res, parent, x, y, parser);
if (key.codes[0] == 10) {
mEnterKey = key;
}
return key;
}
/**
* This looks at the ime options given by the current editor, to set the
* appropriate label on the keyboard's enter key (if it has one).
*/
void setImeOptions(Resources res, int options) {
if (mEnterKey == null) {
return;
}
switch (options&(EditorInfo.IME_MASK_ACTION|EditorInfo.IME_FLAG_NO_ENTER_ACTION)) {
case EditorInfo.IME_ACTION_GO:
mEnterKey.iconPreview = null;
mEnterKey.icon = null;
mEnterKey.label = res.getText(R.string.label_go_key);
break;
case EditorInfo.IME_ACTION_NEXT:
mEnterKey.iconPreview = null;
mEnterKey.icon = null;
mEnterKey.label = res.getText(R.string.label_next_key);
break;
case EditorInfo.IME_ACTION_SEARCH:
mEnterKey.icon = res.getDrawable(
R.drawable.sym_keyboard_search);
mEnterKey.label = null;
break;
case EditorInfo.IME_ACTION_SEND:
mEnterKey.iconPreview = null;
mEnterKey.icon = null;
mEnterKey.label = res.getText(R.string.label_send_key);
break;
default:
mEnterKey.icon = res.getDrawable(
R.drawable.sym_keyboard_return);
mEnterKey.label = null;
break;
}
} }
static class LatinKey extends Keyboard.Key { static class LatinKey extends Keyboard.Key {

View File

@@ -27,6 +27,7 @@ import android.view.View;
import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -64,20 +65,28 @@ public class SoftKeyboard extends InputMethodService
private long mLastShiftTime; private long mLastShiftTime;
private long mMetaState; private long mMetaState;
private Keyboard mSymbolsKeyboard; private LatinKeyboard mSymbolsKeyboard;
private Keyboard mSymbolsShiftedKeyboard; private LatinKeyboard mSymbolsShiftedKeyboard;
private Keyboard mQwertyKeyboard; private LatinKeyboard mQwertyKeyboard;
private Keyboard mCurKeyboard; private LatinKeyboard mCurKeyboard;
private String mWordSeparators; private String mWordSeparators;
/** /**
* Helper function to generate the various keyboard layouts used by the * Main initialization of the input method component. Be sure to call
* input method. Takes care of regenerating the layouts if the width * to super class.
* of the input method changes.
*/ */
private void makeKeyboards() { @Override public void onCreate() {
super.onCreate();
mWordSeparators = getResources().getString(R.string.word_separators);
}
/**
* This is the point where you can do all of your UI initialization. It
* is called after creation and any configuration change.
*/
@Override public void onInitializeInterface() {
if (mQwertyKeyboard != null) { if (mQwertyKeyboard != null) {
// Configuration changes can happen after the keyboard gets recreated, // Configuration changes can happen after the keyboard gets recreated,
// so we need to be able to re-build the keyboards if the available // so we need to be able to re-build the keyboards if the available
@@ -91,16 +100,6 @@ public class SoftKeyboard extends InputMethodService
mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift); mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift);
} }
/**
* Main initialization of the input method component. Be sure to call
* to super class.
*/
@Override public void onCreate() {
super.onCreate();
makeKeyboards();
mWordSeparators = getResources().getString(R.string.word_separators);
}
/** /**
* Called by the framework when your view for creating input needs to * Called by the framework when your view for creating input needs to
* be generated. This will be called the first time your input method * be generated. This will be called the first time your input method
@@ -108,9 +107,6 @@ public class SoftKeyboard extends InputMethodService
* a configuration change. * a configuration change.
*/ */
@Override public View onCreateInputView() { @Override public View onCreateInputView() {
// We call makeKeyboards() here to regenerate them if needed due to
// a configuration change.
makeKeyboards();
mInputView = (KeyboardView) getLayoutInflater().inflate( mInputView = (KeyboardView) getLayoutInflater().inflate(
R.layout.input, null); R.layout.input, null);
mInputView.setOnKeyboardActionListener(this); mInputView.setOnKeyboardActionListener(this);
@@ -178,14 +174,16 @@ public class SoftKeyboard extends InputMethodService
// We now look for a few special variations of text that will // We now look for a few special variations of text that will
// modify our behavior. // modify our behavior.
int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION; int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION;
if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD) { if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD ||
variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
// Do not display predictions / what the user is typing // Do not display predictions / what the user is typing
// when they are entering a password. // when they are entering a password.
mPredictionOn = false; mPredictionOn = false;
} }
if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|| variation == EditorInfo.TYPE_TEXT_VARIATION_URI) { || variation == EditorInfo.TYPE_TEXT_VARIATION_URI
|| variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) {
// Our predictions are not useful for e-mail addresses // Our predictions are not useful for e-mail addresses
// or URIs. // or URIs.
mPredictionOn = false; mPredictionOn = false;
@@ -211,7 +209,12 @@ public class SoftKeyboard extends InputMethodService
// For all unknown input types, default to the alphabetic // For all unknown input types, default to the alphabetic
// keyboard with no special features. // keyboard with no special features.
mCurKeyboard = mQwertyKeyboard; mCurKeyboard = mQwertyKeyboard;
updateShiftKeyState(attribute);
} }
// Update the label on the enter key, depending on what the application
// says it will do.
mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions);
} }
/** /**
@@ -250,6 +253,8 @@ public class SoftKeyboard extends InputMethodService
@Override public void onUpdateSelection(int oldSelStart, int oldSelEnd, @Override public void onUpdateSelection(int oldSelStart, int oldSelEnd,
int newSelStart, int newSelEnd, int newSelStart, int newSelEnd,
int candidatesStart, int candidatesEnd) { int candidatesStart, int candidatesEnd) {
super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
candidatesStart, candidatesEnd);
// If the current selection in the text view changes, we should // If the current selection in the text view changes, we should
// clear whatever candidate text we have. // clear whatever candidate text we have.
@@ -362,6 +367,26 @@ public class SoftKeyboard extends InputMethodService
// text being entered with a hard keyboard, we need to process // text being entered with a hard keyboard, we need to process
// it and do the appropriate action. // it and do the appropriate action.
if (PROCESS_HARD_KEYS) { if (PROCESS_HARD_KEYS) {
if (keyCode == KeyEvent.KEYCODE_SPACE
&& (event.getMetaState()&KeyEvent.META_ALT_ON) != 0) {
// A silly example: in our input method, Alt+Space
// is a shortcut for 'android' in lower case.
InputConnection ic = getCurrentInputConnection();
if (ic != null) {
// First, tell the editor that it is no longer in the
// shift state, since we are consuming this.
ic.clearMetaKeyStates(KeyEvent.META_ALT_ON);
keyDownUp(KeyEvent.KEYCODE_A);
keyDownUp(KeyEvent.KEYCODE_N);
keyDownUp(KeyEvent.KEYCODE_D);
keyDownUp(KeyEvent.KEYCODE_R);
keyDownUp(KeyEvent.KEYCODE_O);
keyDownUp(KeyEvent.KEYCODE_I);
keyDownUp(KeyEvent.KEYCODE_D);
// And we consume this event.
return true;
}
}
if (mPredictionOn && translateKeyDown(keyCode, event)) { if (mPredictionOn && translateKeyDown(keyCode, event)) {
return true; return true;
} }
@@ -408,7 +433,11 @@ public class SoftKeyboard extends InputMethodService
private void updateShiftKeyState(EditorInfo attr) { private void updateShiftKeyState(EditorInfo attr) {
if (attr != null if (attr != null
&& mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) { && mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) {
int caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType); int caps = 0;
EditorInfo ei = getCurrentInputEditorInfo();
if (ei != null && ei.inputType != EditorInfo.TYPE_NULL) {
caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType);
}
mInputView.setShifted(mCapsLock || caps != 0); mInputView.setShifted(mCapsLock || caps != 0);
} }
} }
@@ -488,6 +517,18 @@ public class SoftKeyboard extends InputMethodService
} }
} }
public void onText(CharSequence text) {
InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
ic.beginBatchEdit();
if (mComposing.length() > 0) {
commitTyped(ic);
}
ic.commitText(text, 0);
ic.endBatchEdit();
updateShiftKeyState(getCurrentInputEditorInfo());
}
/** /**
* Update the list of available candidates from the current composing * Update the list of available candidates from the current composing
* text. This will need to be filled in by however you are determining * text. This will need to be filled in by however you are determining
@@ -521,7 +562,7 @@ public class SoftKeyboard extends InputMethodService
final int length = mComposing.length(); final int length = mComposing.length();
if (length > 1) { if (length > 1) {
mComposing.delete(length - 1, length); mComposing.delete(length - 1, length);
getCurrentInputConnection().setComposingText(mComposing, mComposing.length()); getCurrentInputConnection().setComposingText(mComposing, 1);
updateCandidates(); updateCandidates();
} else if (length > 0) { } else if (length > 0) {
mComposing.setLength(0); mComposing.setLength(0);
@@ -562,7 +603,7 @@ public class SoftKeyboard extends InputMethodService
} }
if (isAlphabet(primaryCode) && mPredictionOn) { if (isAlphabet(primaryCode) && mPredictionOn) {
mComposing.append((char) primaryCode); mComposing.append((char) primaryCode);
getCurrentInputConnection().setComposingText(mComposing, mComposing.length()); getCurrentInputConnection().setComposingText(mComposing, 1);
updateShiftKeyState(getCurrentInputEditorInfo()); updateShiftKeyState(getCurrentInputEditorInfo());
updateCandidates(); updateCandidates();
} else { } else {
@@ -573,7 +614,7 @@ public class SoftKeyboard extends InputMethodService
private void handleClose() { private void handleClose() {
commitTyped(getCurrentInputConnection()); commitTyped(getCurrentInputConnection());
dismissSoftInput(0); requestHideSelf(0);
mInputView.closing(); mInputView.closing();
} }

View File

@@ -108,6 +108,8 @@ void PropertyServer::SetDefaultProperties(void)
{ "ro.SECONDARY_SERVER_MEM", "4096" }, { "ro.SECONDARY_SERVER_MEM", "4096" },
{ "ro.HIDDEN_APP_MEM", "8192" }, { "ro.HIDDEN_APP_MEM", "8192" },
{ "ro.EMPTY_APP_MEM", "16384" }, { "ro.EMPTY_APP_MEM", "16384" },
{ "ro.HOME_APP_ADJ", "4" },
{ "ro.HOME_APP_MEM", "4096" },
//{ "init.svc.adbd", "running" }, // causes ADB-JDWP //{ "init.svc.adbd", "running" }, // causes ADB-JDWP
{ "init.svc.usbd", "running" }, { "init.svc.usbd", "running" },
{ "init.svc.debuggerd", "running" }, { "init.svc.debuggerd", "running" },
@@ -132,7 +134,7 @@ void PropertyServer::SetDefaultProperties(void)
{ "dalvik.vm.stack-trace-file", "/data/anr/traces.txt" }, { "dalvik.vm.stack-trace-file", "/data/anr/traces.txt" },
//{ "dalvik.vm.execution-mode", "int:portable" }, //{ "dalvik.vm.execution-mode", "int:portable" },
{ "dalvik.vm.enableassertions", "all" }, // -ea { "dalvik.vm.enableassertions", "all" }, // -ea
{ "dalvik.vm.verify-bytecode", "false" }, // -Xverify { "dalvik.vm.dexopt-flags", "" }, // e.g. "v=a,o=v,m=n"
{ "dalvik.vm.deadlock-predict", "off" }, // -Xdeadlockpredict { "dalvik.vm.deadlock-predict", "off" }, // -Xdeadlockpredict
//{ "dalvik.vm.jniopts", "forcecopy" }, // -Xjniopts //{ "dalvik.vm.jniopts", "forcecopy" }, // -Xjniopts
{ "log.redirect-stdio", "false" }, // -Xlog-stdio { "log.redirect-stdio", "false" }, // -Xlog-stdio

View File

@@ -1,7 +1,7 @@
/* /*
* Copyright 2007 The Android Open Source Project * Copyright 2007 The Android Open Source Project
* *
* Magic entries in /sys/android_power/. * Magic entries in /sys/class/power_supply/.
*/ */
#include "Common.h" #include "Common.h"
@@ -12,30 +12,6 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#if 0
/*
* Set of entries found in /sys/android_power.
*/
typedef enum DeviceIndex {
kPowerUnknown = 0,
kPowerAutoOffTimeout,
kPowerBatteryLevel,
kPowerBatteryLevelLow,
kPowerBatteryLevelRaw,
kPowerBatteryLevelScale,
kPowerBatteryLowLevel,
kPowerBatteryShutdownLevel,
kPowerChargingState,
kPowerRequestState,
kPowerState,
kPowerAcquireFullWakeLock,
kPowerAcquirePartialWakeLock,
kPowerReleaseWakeLock,
} DeviceIndex;
#endif
/* /*
* Map filename to device index. * Map filename to device index.
* *
@@ -47,38 +23,26 @@ static const struct {
//DeviceIndex idx; //DeviceIndex idx;
const char* data; const char* data;
} gDeviceMap[] = { } gDeviceMap[] = {
{ "auto_off_timeout", //kPowerAutoOffTimeout, { "ac/online",
"\n" },
{ "battery_level", //kPowerBatteryLevel,
"9\n" },
{ "battery_level_low", //kPowerBatteryLevelLow,
"0\n" }, "0\n" },
{ "battery_level_raw", //kPowerBatteryLevelRaw,
{ "battery/batt_temp",
"281\n", },
{ "battery/batt_vol",
"4170\n" },
{ "battery/capacity",
"100\n" }, "100\n" },
{ "battery_level_scale", //kPowerBatteryLevelScale, { "battery/health",
"9\n" }, "Good\n" },
{ "battery_low_level", //kPowerBatteryLowLevel, { "battery/present",
"10\n" }, "0\n" },
{ "battery_shutdown_level", //kPowerBatteryShutdownLevel, { "battery/status",
"5\n", }, "Full" },
{ "charging_state", //kPowerChargingState, { "battery/technology",
"Maintaining\n" }, "Li-ion\n" },
{ "request_state", //kPowerRequestState,
"wake\n" },
{ "state", //kPowerState,
"0-1-0\n" },
{ "acquire_full_wake_lock", //kPowerAcquireFullWakeLock,
"\n" },
{ "acquire_partial_wake_lock", //kPowerAcquirePartialWakeLock,
"\n" },
{ "release_wake_lock", //kPowerReleaseWakeLock,
"radio-interface PowerManagerService KeyEvents\n" },
{ "wait_for_fb_sleep", //kSleepFileName,
"" }, // this means "block forever on read"
{ "wait_for_fb_wake", //kWakeFileName,
"0" },
{ "usb/online",
"1\n" },
}; };
/* /*
@@ -96,7 +60,7 @@ typedef struct PowerState {
*/ */
static void configureInitialState(const char* pathName, PowerState* powerState) static void configureInitialState(const char* pathName, PowerState* powerState)
{ {
const char* cp = pathName + strlen("/sys/android_power/"); const char* cp = pathName + strlen("/sys/class/power_supply/");
int i; int i;
powerState->which = -1; powerState->which = -1;
@@ -134,8 +98,11 @@ static ssize_t readPower(FakeDev* dev, int fd, void* buf, size_t count)
wsLog("%s: read %d\n", dev->debugName, count); wsLog("%s: read %d\n", dev->debugName, count);
if (state->which < 0 || state->which >= sizeof(gDeviceMap)/sizeof(gDeviceMap[0])) if (state->which < 0 ||
state->which >= (int) (sizeof(gDeviceMap)/sizeof(gDeviceMap[0])))
{
return 0; return 0;
}
const char* data = gDeviceMap[state->which].data; const char* data = gDeviceMap[state->which].data;
size_t strLen = strlen(data); size_t strLen = strlen(data);

View File

@@ -47,10 +47,6 @@ resources.)
* Devices we intercept. * Devices we intercept.
* *
* Needed: * Needed:
* /sys/android_power/battery_level_scale
* /sys/android_power/battery_level
* /sys/android_power/battery_level_raw
* /sys/android_power/charging_state
* /dev/alarm * /dev/alarm
* radio * radio
*/ */
@@ -70,7 +66,7 @@ FakedPath fakedpaths[] =
{ "/dev/input/event0", wsOpenDevEvent }, { "/dev/input/event0", wsOpenDevEvent },
{ "/dev/input/*", NULL }, { "/dev/input/*", NULL },
{ "/dev/log/*", wsOpenDevLog }, { "/dev/log/*", wsOpenDevLog },
{ "/sys/android_power/*", wsOpenDevPower }, { "/sys/class/power_supply/*", wsOpenDevPower },
{ "/sys/devices/platform/android-vibrator/enable", wsOpenDevVibrator }, { "/sys/devices/platform/android-vibrator/enable", wsOpenDevVibrator },
{ "/sys/qemu_trace/*", NULL }, { "/sys/qemu_trace/*", NULL },
{ NULL, NULL } { NULL, NULL }

347
testrunner/adb_interface.py Executable file
View File

@@ -0,0 +1,347 @@
#!/usr/bin/python2.4
#
#
# Copyright 2008, 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.
"""Provides an interface to communicate with the device via the adb command.
Assumes adb binary is currently on system path.
"""
# Python imports
import os
import string
import time
# local imports
import am_instrument_parser
import errors
import logger
import run_command
class AdbInterface:
"""Helper class for communicating with Android device via adb."""
# argument to pass to adb, to direct command to specific device
_target_arg = ""
DEVICE_TRACE_DIR = "/data/test_results/"
def SetEmulatorTarget(self):
"""Direct all future commands to the only running emulator."""
self._target_arg = "-e"
def SetDeviceTarget(self):
"""Direct all future commands to the only connected USB device."""
self._target_arg = "-d"
def SetTargetSerial(self, serial):
"""Direct all future commands to Android target with the given serial."""
self._target_arg = "-s %s" % serial
def SendCommand(self, command_string, timeout_time=20, retry_count=3):
"""Send a command via adb.
Args:
command_string: adb command to run
timeout_time: number of seconds to wait for command to respond before
retrying
retry_count: number of times to retry command before raising
WaitForResponseTimedOutError
Returns:
string output of command
Raises:
WaitForResponseTimedOutError if device does not respond to command
"""
adb_cmd = "adb %s %s" % (self._target_arg, command_string)
logger.SilentLog("about to run %s" % adb_cmd)
return run_command.RunCommand(adb_cmd, timeout_time=timeout_time,
retry_count=retry_count)
def SendShellCommand(self, cmd, timeout_time=20, retry_count=3):
"""Send a adb shell command.
Args:
cmd: adb shell command to run
timeout_time: number of seconds to wait for command to respond before
retrying
retry_count: number of times to retry command before raising
WaitForResponseTimedOutError
Returns:
string output of command
Raises:
WaitForResponseTimedOutError: if device does not respond to command
"""
return self.SendCommand("shell %s" % cmd, timeout_time=timeout_time,
retry_count=retry_count)
def BugReport(self, path):
"""Dumps adb bugreport to the file specified by the path.
Args:
path: Path of the file where adb bugreport is dumped to.
"""
bug_output = self.SendShellCommand("bugreport", timeout_time=60)
bugreport_file = open(path, "w")
bugreport_file.write(bug_output)
bugreport_file.close()
def Push(self, src, dest):
"""Pushes the file src onto the device at dest.
Args:
src: file path of host file to push
dest: destination absolute file path on device
"""
self.SendCommand("push %s %s" % (src, dest), timeout_time=60)
def Pull(self, src, dest):
"""Pulls the file src on the device onto dest on the host.
Args:
src: absolute file path of file on device to pull
dest: destination file path on host
Returns:
True if success and False otherwise.
"""
# Create the base dir if it doesn't exist already
if not os.path.exists(os.path.dirname(dest)):
os.makedirs(os.path.dirname(dest))
if self.DoesFileExist(src):
self.SendCommand("pull %s %s" % (src, dest), timeout_time=60)
return True
else:
logger.Log("ADB Pull Failed: Source file %s does not exist." % src)
return False
def DoesFileExist(self, src):
"""Checks if the given path exists on device target.
Args:
src: file path to be checked.
Returns:
True if file exists
"""
output = self.SendShellCommand("ls %s" % src)
error = "No such file or directory"
if error in output:
return False
return True
def StartInstrumentationForPackage(
self, package_name, runner_name, timeout_time=60*10,
no_window_animation=False, instrumentation_args={}):
"""Run instrumentation test for given package and runner.
Equivalent to StartInstrumentation, except instrumentation path is
separated into its package and runner components.
"""
instrumentation_path = "%s/%s" % (package_name, runner_name)
return self.StartInstrumentation(self, instrumentation_path, timeout_time,
no_window_animation, instrumentation_args)
def StartInstrumentation(
self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
profile=False, instrumentation_args={}):
"""Runs an instrumentation class on the target.
Returns a dictionary containing the key value pairs from the
instrumentations result bundle and a list of TestResults. Also handles the
interpreting of error output from the device and raises the necessary
exceptions.
Args:
instrumentation_path: string. It should be the fully classified package
name, and instrumentation test runner, separated by "/"
e.g. com.android.globaltimelaunch/.GlobalTimeLaunch
timeout_time: Timeout value for the am command.
no_window_animation: boolean, Whether you want window animations enabled
or disabled
profile: If True, profiling will be turned on for the instrumentation.
instrumentation_args: Dictionary of key value bundle arguments to pass to
instrumentation.
Returns:
(test_results, inst_finished_bundle)
test_results: a list of TestResults
inst_finished_bundle (dict): Key/value pairs contained in the bundle that
is passed into ActivityManager.finishInstrumentation(). Included in this
bundle is the return code of the Instrumentation process, any error
codes reported by the activity manager, and any results explicitly added
by the instrumentation code.
Raises:
WaitForResponseTimedOutError: if timeout occurred while waiting for
response to adb instrument command
DeviceUnresponsiveError: if device system process is not responding
InstrumentationError: if instrumentation failed to run
"""
command_string = self._BuildInstrumentationCommandPath(
instrumentation_path, no_window_animation=no_window_animation,
profile=profile, raw_mode=True,
instrumentation_args=instrumentation_args)
(test_results, inst_finished_bundle) = (
am_instrument_parser.ParseAmInstrumentOutput(
self.SendShellCommand(command_string, timeout_time=timeout_time,
retry_count=2)))
if "code" not in inst_finished_bundle:
raise errors.InstrumentationError("no test results... device setup "
"correctly?")
if inst_finished_bundle["code"] == "0":
short_msg_result = "no error message"
if "shortMsg" in inst_finished_bundle:
short_msg_result = inst_finished_bundle["shortMsg"]
logger.Log(short_msg_result)
raise errors.InstrumentationError(short_msg_result)
if "INSTRUMENTATION_ABORTED" in inst_finished_bundle:
logger.Log("INSTRUMENTATION ABORTED!")
raise errors.DeviceUnresponsiveError
return (test_results, inst_finished_bundle)
def StartInstrumentationNoResults(
self, package_name, runner_name, no_window_animation=False,
raw_mode=False, instrumentation_args={}):
"""Runs instrumentation and dumps output to stdout.
Equivalent to StartInstrumentation, but will dump instrumentation
'normal' output to stdout, instead of parsing return results. Command will
never timeout.
"""
adb_command_string = self.PreviewInstrumentationCommand(
package_name, runner_name, no_window_animation=no_window_animation,
raw_mode=raw_mode, instrumentation_args=instrumentation_args)
logger.Log(adb_command_string)
run_command.RunCommand(adb_command_string, return_output=False)
def PreviewInstrumentationCommand(
self, package_name, runner_name, no_window_animation=False,
raw_mode=False, instrumentation_args={}):
"""Returns a string of adb command that will be executed."""
inst_command_string = self._BuildInstrumentationCommand(
package_name, runner_name, no_window_animation=no_window_animation,
raw_mode=raw_mode, instrumentation_args=instrumentation_args)
command_string = "adb %s shell %s" % (self._target_arg, inst_command_string)
return command_string
def _BuildInstrumentationCommand(
self, package, runner_name, no_window_animation=False, profile=False,
raw_mode=True, instrumentation_args={}):
instrumentation_path = "%s/%s" % (package, runner_name)
return self._BuildInstrumentationCommandPath(
instrumentation_path, no_window_animation=no_window_animation,
profile=profile, raw_mode=raw_mode,
instrumentation_args=instrumentation_args)
def _BuildInstrumentationCommandPath(
self, instrumentation_path, no_window_animation=False, profile=False,
raw_mode=True, instrumentation_args={}):
command_string = "am instrument"
if no_window_animation:
command_string += " --no_window_animation"
if profile:
self._CreateTraceDir()
command_string += (
" -p %s/%s.dmtrace" %
(self.DEVICE_TRACE_DIR, instrumentation_path.split(".")[-1]))
for key, value in instrumentation_args.items():
command_string += " -e %s %s" % (key, value)
if raw_mode:
command_string += " -r"
command_string += " -w %s" % instrumentation_path
return command_string
def _CreateTraceDir(self):
ls_response = self.SendShellCommand("ls /data/trace")
if ls_response.strip("#").strip(string.whitespace) != "":
self.SendShellCommand("create /data/trace", "mkdir /data/trace")
self.SendShellCommand("make /data/trace world writeable",
"chmod 777 /data/trace")
def WaitForDevicePm(self, wait_time=120):
"""Waits for targeted device's package manager to be up.
Args:
wait_time: time in seconds to wait
Raises:
WaitForResponseTimedOutError if wait_time elapses and pm still does not
respond.
"""
logger.Log("Waiting for device package manager for %s seconds..."
% wait_time)
self.SendCommand("wait-for-device")
# Now the device is there, but may not be running.
# Query the package manager with a basic command
pm_found = False
attempts = 0
wait_period = 5
while not pm_found and (attempts*wait_period) < wait_time:
# assume the 'adb shell pm path android' command will always
# return 'package: something' in the success case
output = self.SendShellCommand("pm path android", retry_count=1)
if "package:" in output:
pm_found = True
else:
time.sleep(wait_period)
attempts += 1
if not pm_found:
raise errors.WaitForResponseTimedOutError
def Sync(self, retry_count=3):
"""Perform a adb sync.
Blocks until device package manager is responding.
Args:
retry_count: number of times to retry sync before failing
Raises:
WaitForResponseTimedOutError if package manager does not respond
"""
output = self.SendCommand("sync", retry_count=retry_count)
if "Read-only file system" in output:
logger.SilentLog(output)
logger.Log("adb sync failed due to read only fs, retrying")
self.SendCommand("remount")
output = self.SendCommand("sync", retry_count=retry_count)
if "No space left on device" in output:
logger.SilentLog(output)
logger.Log("adb sync failed due to no space on device, trying shell" +
" start/stop")
self.SendShellCommand("stop", retry_count=retry_count)
output = self.SendCommand("sync", retry_count=retry_count)
self.SendShellCommand("start", retry_count=retry_count)
logger.SilentLog(output)
self.WaitForDevicePm()
return output

View File

@@ -0,0 +1,178 @@
#!/usr/bin/python2.4
#
#
# Copyright 2008, 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.
"""Module that assists in parsing the output of "am instrument" commands run on
the device."""
import re
import string
def ParseAmInstrumentOutput(result):
"""Given the raw output of an "am instrument" command that targets and
InstrumentationTestRunner, return structured data.
Args:
result (string): Raw output of "am instrument"
Return
(test_results, inst_finished_bundle)
test_results (list of am_output_parser.TestResult)
inst_finished_bundle (dict): Key/value pairs contained in the bundle that is
passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return
code of the Instrumentation process, any error codes reported by the
activity manager, and any results explicity added by the instrumentation
code.
"""
re_status_code = re.compile(r'INSTRUMENTATION_STATUS_CODE: (?P<status_code>-?\d)$')
test_results = []
inst_finished_bundle = {}
result_block_string = ""
for line in result.splitlines():
result_block_string += line + '\n'
if "INSTRUMENTATION_STATUS_CODE:" in line:
test_result = TestResult(result_block_string)
if test_result.GetStatusCode() == 1: # The test started
pass
elif test_result.GetStatusCode() in [0, -1, -2]:
test_results.append(test_result)
else:
pass
result_block_string = ""
if "INSTRUMENTATION_CODE:" in line:
inst_finished_bundle = _ParseInstrumentationFinishedBundle(result_block_string)
result_block_string = ""
return (test_results, inst_finished_bundle)
def _ParseInstrumentationFinishedBundle(result):
"""Given the raw output of "am instrument" returns a dictionary of the
key/value pairs from the bundle passed into
ActivityManager.finishInstrumentation().
Args:
result (string): Raw output of "am instrument"
Return:
inst_finished_bundle (dict): Key/value pairs contained in the bundle that is
passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return
code of the Instrumentation process, any error codes reported by the
activity manager, and any results explicity added by the instrumentation
code.
"""
re_result = re.compile(r'INSTRUMENTATION_RESULT: ([^=]+)=(.+)$')
re_code = re.compile(r'INSTRUMENTATION_CODE: (\-?\d)$')
result_dict = {}
key = ''
val = ''
last_tag = ''
for line in result.split('\n'):
line = line.strip(string.whitespace)
if re_result.match(line):
last_tag = 'INSTRUMENTATION_RESULT'
key = re_result.search(line).group(1).strip(string.whitespace)
if key.startswith('performance.'):
key = key[len('performance.'):]
val = re_result.search(line).group(2).strip(string.whitespace)
try:
result_dict[key] = float(val)
except ValueError:
result_dict[key] = val
except TypeError:
result_dict[key] = val
elif re_code.match(line):
last_tag = 'INSTRUMENTATION_CODE'
key = 'code'
val = re_code.search(line).group(1).strip(string.whitespace)
result_dict[key] = val
elif 'INSTRUMENTATION_ABORTED:' in line:
last_tag = 'INSTRUMENTATION_ABORTED'
key = 'INSTRUMENTATION_ABORTED'
val = ''
result_dict[key] = val
elif last_tag == 'INSTRUMENTATION_RESULT':
result_dict[key] += '\n' + line
if not result_dict.has_key('code'):
result_dict['code'] = '0'
result_dict['shortMsg'] = "No result returned from instrumentation"
return result_dict
class TestResult(object):
"""A class that contains information about a single test result."""
def __init__(self, result_block_string):
"""
Args:
result_block_string (string): Is a single "block" of output. A single
"block" would be either a "test started" status report, or a "test
finished" status report.
"""
self._test_name = None
self._status_code = None
self._failure_reason = None
re_start_block = re.compile(
r'\s*INSTRUMENTATION_STATUS: stream=(?P<stream>.*)'
'INSTRUMENTATION_STATUS: test=(?P<test>\w+)\s+'
'INSTRUMENTATION_STATUS: class=(?P<class>[\w\.]+)\s+'
'INSTRUMENTATION_STATUS: current=(?P<current>\d+)\s+'
'INSTRUMENTATION_STATUS: numtests=(?P<numtests>\d+)\s+'
'INSTRUMENTATION_STATUS: id=.*\s+'
'INSTRUMENTATION_STATUS_CODE: 1\s*', re.DOTALL)
re_end_block = re.compile(
r'\s*INSTRUMENTATION_STATUS: stream=(?P<stream>.*)'
'INSTRUMENTATION_STATUS: test=(?P<test>\w+)\s+'
'(INSTRUMENTATION_STATUS: stack=(?P<stack>.*))?'
'INSTRUMENTATION_STATUS: class=(?P<class>[\w\.]+)\s+'
'INSTRUMENTATION_STATUS: current=(?P<current>\d+)\s+'
'INSTRUMENTATION_STATUS: numtests=(?P<numtests>\d+)\s+'
'INSTRUMENTATION_STATUS: id=.*\s+'
'INSTRUMENTATION_STATUS_CODE: (?P<status_code>0|-1|-2)\s*', re.DOTALL)
start_block_match = re_start_block.match(result_block_string)
end_block_match = re_end_block.match(result_block_string)
if start_block_match:
self._test_name = "%s:%s" % (start_block_match.group('class'),
start_block_match.group('test'))
self._status_code = 1
elif end_block_match:
self._test_name = "%s:%s" % (end_block_match.group('class'),
end_block_match.group('test'))
self._status_code = int(end_block_match.group('status_code'))
self._failure_reason = end_block_match.group('stack')
def GetTestName(self):
return self._test_name
def GetStatusCode(self):
return self._status_code
def GetFailureReason(self):
return self._failure_reason

312
testrunner/coverage.py Executable file
View File

@@ -0,0 +1,312 @@
#!/usr/bin/python2.4
#
#
# Copyright 2008, 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.
"""Utilities for generating code coverage reports for Android tests."""
# Python imports
import glob
import optparse
import os
# local imports
import android_build
import coverage_targets
import errors
import logger
import run_command
class CoverageGenerator(object):
"""Helper utility for obtaining code coverage results on Android.
Intended to simplify the process of building,running, and generating code
coverage results for a pre-defined set of tests and targets
"""
# environment variable to enable emma builds in Android build system
_EMMA_BUILD_FLAG = "EMMA_INSTRUMENT"
# build path to Emma target Makefile
_EMMA_BUILD_PATH = os.path.join("external", "emma")
# path to EMMA host jar, relative to Android build root
_EMMA_JAR = os.path.join(_EMMA_BUILD_PATH, "lib", "emma.jar")
_TEST_COVERAGE_EXT = "ec"
# default device-side path to code coverage results file
_DEVICE_COVERAGE_PATH = "/sdcard/coverage.ec"
# root path of generated coverage report files, relative to Android build root
_COVERAGE_REPORT_PATH = os.path.join("out", "emma")
_CORE_TARGET_PATH = os.path.join("development", "testrunner",
"coverage_targets.xml")
# vendor glob file path patterns to tests, relative to android
# build root
_VENDOR_TARGET_PATH = os.path.join("vendor", "*", "tests", "testinfo",
"coverage_targets.xml")
# path to root of target build intermediates
_TARGET_INTERMEDIATES_BASE_PATH = os.path.join("out", "target", "common",
"obj")
def __init__(self, android_root_path, adb_interface):
self._root_path = android_root_path
self._output_root_path = os.path.join(self._root_path,
self._COVERAGE_REPORT_PATH)
self._emma_jar_path = os.path.join(self._root_path, self._EMMA_JAR)
self._adb = adb_interface
self._targets_manifest = self._ReadTargets()
def EnableCoverageBuild(self):
"""Enable building an Android target with code coverage instrumentation."""
os.environ[self._EMMA_BUILD_FLAG] = "true"
def ExtractReport(self, test_suite,
device_coverage_path=_DEVICE_COVERAGE_PATH,
output_path=None):
"""Extract runtime coverage data and generate code coverage report.
Assumes test has just been executed.
Args:
test_suite: TestSuite to generate coverage data for
device_coverage_path: location of coverage file on device
output_path: path to place output files in. If None will use
<android_root_path>/<_COVERAGE_REPORT_PATH>/<target>/<test>
Returns:
absolute file path string of generated html report file.
"""
if output_path is None:
output_path = os.path.join(self._root_path,
self._COVERAGE_REPORT_PATH,
test_suite.GetTargetName(),
test_suite.GetName())
coverage_local_name = "%s.%s" % (test_suite.GetName(),
self._TEST_COVERAGE_EXT)
coverage_local_path = os.path.join(output_path,
coverage_local_name)
if self._adb.Pull(device_coverage_path, coverage_local_path):
report_path = os.path.join(output_path,
test_suite.GetName())
target = self._targets_manifest.GetTarget(test_suite.GetTargetName())
return self._GenerateReport(report_path, coverage_local_path, [target],
do_src=True)
return None
def _GenerateReport(self, report_path, coverage_file_path, targets,
do_src=True):
"""Generate the code coverage report.
Args:
report_path: absolute file path of output file, without extension
coverage_file_path: absolute file path of code coverage result file
targets: list of CoverageTargets to use as base for code coverage
measurement.
do_src: True if generate coverage report with source linked in.
Note this will increase size of generated report.
Returns:
absolute file path to generated report file.
"""
input_metadatas = self._GatherMetadatas(targets)
if do_src:
src_arg = self._GatherSrcs(targets)
else:
src_arg = ""
report_file = "%s.html" % report_path
cmd1 = ("java -cp %s emma report -r html -in %s %s %s " %
(self._emma_jar_path, coverage_file_path, input_metadatas, src_arg))
cmd2 = "-Dreport.html.out.file=%s" % report_file
self._RunCmd(cmd1 + cmd2)
return report_file
def _GatherMetadatas(self, targets):
"""Builds the emma input metadata argument from provided targets.
Args:
targets: list of CoverageTargets
Returns:
input metadata argument string
"""
input_metadatas = ""
for target in targets:
input_metadata = os.path.join(self._GetBuildIntermediatePath(target),
"coverage.em")
input_metadatas += " -in %s" % input_metadata
return input_metadatas
def _GetBuildIntermediatePath(self, target):
return os.path.join(
self._root_path, self._TARGET_INTERMEDIATES_BASE_PATH, target.GetType(),
"%s_intermediates" % target.GetName())
def _GatherSrcs(self, targets):
"""Builds the emma input source path arguments from provided targets.
Args:
targets: list of CoverageTargets
Returns:
source path arguments string
"""
src_list = []
for target in targets:
target_srcs = target.GetPaths()
for path in target_srcs:
src_list.append("-sp %s" % os.path.join(self._root_path, path))
return " ".join(src_list)
def _MergeFiles(self, input_paths, dest_path):
"""Merges a set of emma coverage files into a consolidated file.
Args:
input_paths: list of string absolute coverage file paths to merge
dest_path: absolute file path of destination file
"""
input_list = []
for input_path in input_paths:
input_list.append("-in %s" % input_path)
input_args = " ".join(input_list)
self._RunCmd("java -cp %s emma merge %s -out %s" % (self._emma_jar_path,
input_args, dest_path))
def _RunCmd(self, cmd):
"""Runs and logs the given os command."""
run_command.RunCommand(cmd, return_output=False)
def _CombineTargetCoverage(self):
"""Combines all target mode code coverage results.
Will find all code coverage data files in direct sub-directories of
self._output_root_path, and combine them into a single coverage report.
Generated report is placed at self._output_root_path/android.html
"""
coverage_files = self._FindCoverageFiles(self._output_root_path)
combined_coverage = os.path.join(self._output_root_path,
"android.%s" % self._TEST_COVERAGE_EXT)
self._MergeFiles(coverage_files, combined_coverage)
report_path = os.path.join(self._output_root_path, "android")
# don't link to source, to limit file size
self._GenerateReport(report_path, combined_coverage,
self._targets_manifest.GetTargets(), do_src=False)
def _CombineTestCoverage(self):
"""Consolidates code coverage results for all target result directories."""
target_dirs = os.listdir(self._output_root_path)
for target_name in target_dirs:
output_path = os.path.join(self._output_root_path, target_name)
target = self._targets_manifest.GetTarget(target_name)
if os.path.isdir(output_path) and target is not None:
coverage_files = self._FindCoverageFiles(output_path)
combined_coverage = os.path.join(output_path, "%s.%s" %
(target_name, self._TEST_COVERAGE_EXT))
self._MergeFiles(coverage_files, combined_coverage)
report_path = os.path.join(output_path, target_name)
self._GenerateReport(report_path, combined_coverage, [target])
else:
logger.Log("%s is not a valid target directory, skipping" % output_path)
def _FindCoverageFiles(self, root_path):
"""Finds all files in <root_path>/*/*.<_TEST_COVERAGE_EXT>.
Args:
root_path: absolute file path string to search from
Returns:
list of absolute file path strings of coverage files
"""
file_pattern = os.path.join(root_path, "*", "*.%s" %
self._TEST_COVERAGE_EXT)
coverage_files = glob.glob(file_pattern)
return coverage_files
def GetEmmaBuildPath(self):
return self._EMMA_BUILD_PATH
def _ReadTargets(self):
"""Parses the set of coverage target data.
Returns:
a CoverageTargets object that contains set of parsed targets.
Raises:
AbortError if a fatal error occurred when parsing the target files.
"""
core_target_path = os.path.join(self._root_path, self._CORE_TARGET_PATH)
try:
targets = coverage_targets.CoverageTargets()
targets.Parse(core_target_path)
vendor_targets_pattern = os.path.join(self._root_path,
self._VENDOR_TARGET_PATH)
target_file_paths = glob.glob(vendor_targets_pattern)
for target_file_path in target_file_paths:
targets.Parse(target_file_path)
return targets
except errors.ParseError:
raise errors.AbortError
def TidyOutput(self):
"""Runs tidy on all generated html files.
This is needed to the html files can be displayed cleanly on a web server.
Assumes tidy is on current PATH.
"""
logger.Log("Tidying output files")
self._TidyDir(self._output_root_path)
def _TidyDir(self, dir_path):
"""Recursively tidy all html files in given dir_path."""
html_file_pattern = os.path.join(dir_path, "*.html")
html_files_iter = glob.glob(html_file_pattern)
for html_file_path in html_files_iter:
os.system("tidy -m -errors -quiet %s" % html_file_path)
sub_dirs = os.listdir(dir_path)
for sub_dir_name in sub_dirs:
sub_dir_path = os.path.join(dir_path, sub_dir_name)
if os.path.isdir(sub_dir_path):
self._TidyDir(sub_dir_path)
def CombineCoverage(self):
"""Create combined coverage reports for all targets and tests."""
self._CombineTestCoverage()
self._CombineTargetCoverage()
def Run():
"""Does coverage operations based on command line args."""
# TODO: do we want to support combining coverage for a single target
try:
parser = optparse.OptionParser(usage="usage: %prog --combine-coverage")
parser.add_option(
"-c", "--combine-coverage", dest="combine_coverage", default=False,
action="store_true", help="Combine coverage results stored given "
"android root path")
parser.add_option(
"-t", "--tidy", dest="tidy", default=False, action="store_true",
help="Run tidy on all generated html files")
options, args = parser.parse_args()
coverage = CoverageGenerator(android_build.GetTop(), None)
if options.combine_coverage:
coverage.CombineCoverage()
if options.tidy:
coverage.TidyOutput()
except errors.AbortError:
logger.SilentLog("Exiting due to AbortError")
if __name__ == "__main__":
Run()

View File

@@ -0,0 +1,131 @@
#!/usr/bin/python2.4
#
#
# Copyright 2008, 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.
import xml.dom.minidom
import xml.parsers
import os
import logger
import errors
class CoverageTargets:
"""Accessor for the code coverage target xml file
Expects the following format:
<targets>
<target
name=""
type="JAVA_LIBRARIES|APPS"
build_path=""
[<src path=""/>] (0..*) - These are relative to build_path. If missing,
assumes 'src'
>/target>
TODO: add more format checking
"""
_TARGET_TAG_NAME = 'coverage_target'
def __init__(self, ):
self._target_map= {}
def __iter__(self):
return iter(self._target_map.values())
def Parse(self, file_path):
"""Parse the coverage target data from from given file path, and add it to
the current object
Args:
file_path: absolute file path to parse
Raises:
errors.ParseError if file_path cannot be parsed
"""
try:
doc = xml.dom.minidom.parse(file_path)
except IOError:
# Error: The results file does not exist
logger.Log('Results file %s does not exist' % file_path)
raise errors.ParseError
except xml.parsers.expat.ExpatError:
logger.Log('Error Parsing xml file: %s ' % file_path)
raise errors.ParseError
target_elements = doc.getElementsByTagName(self._TARGET_TAG_NAME)
for target_element in target_elements:
target = CoverageTarget(target_element)
self._AddTarget(target)
def _AddTarget(self, target):
self._target_map[target.GetName()] = target
def GetBuildTargets(self):
""" returns list of target names """
build_targets = []
for target in self:
build_targets.append(target.GetName())
return build_targets
def GetTargets(self):
""" returns list of CoverageTarget"""
return self._target_map.values()
def GetTarget(self, name):
""" returns CoverageTarget for given name. None if not found """
try:
return self._target_map[name]
except KeyError:
return None
class CoverageTarget:
""" Represents one coverage target definition parsed from xml """
_NAME_ATTR = 'name'
_TYPE_ATTR = 'type'
_BUILD_ATTR = 'build_path'
_SRC_TAG = 'src'
_PATH_ATTR = 'path'
def __init__(self, target_element):
self._name = target_element.getAttribute(self._NAME_ATTR)
self._type = target_element.getAttribute(self._TYPE_ATTR)
self._build_path = target_element.getAttribute(self._BUILD_ATTR)
self._paths = []
self._ParsePaths(target_element)
def GetName(self):
return self._name
def GetPaths(self):
return self._paths
def GetType(self):
return self._type
def GetBuildPath(self):
return self._build_path
def _ParsePaths(self, target_element):
src_elements = target_element.getElementsByTagName(self._SRC_TAG)
for src_element in src_elements:
rel_path = src_element.getAttribute(self._PATH_ATTR)
self._paths.append(os.path.join(self.GetBuildPath(), rel_path))
def Parse(xml_file_path):
"""parses out a file_path class from given path to xml"""
targets = CoverageTargets()
targets.Parse(xml_file_path)
return targets

View File

@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<!--Defines the list of test code coverage targets for core android platform
Intent is to list all modules that are present in a typical 'user' build
TODO: auto-generate this file from build
Expected syntax in this file is
<coverage_targets>
<coverage_target name type build_path
[<src path=""/>] (0..*)
>/coverage_target>
Where
name - unique name of Android target
type - one of JAVA_LIBRARIES,APPS
build_path - path to build directory for this module, relative to android
source tree root
src - optional sub-elements. Contains complete set of source code locations
for target, relative to build_path. If not present, assumes valeu of "src"
-->
<coverage_targets>
<!-- Java libs -->
<coverage_target name="framework" type="JAVA_LIBRARIES"
build_path="frameworks/base">
<src path="core/java" />
<src path="graphics/java" />
<src path="im/java" />
<src path="location/java" />
<src path="media/java" />
<src path="opengl/java" />
<src path="sax/java" />
<src path="telephony/java" />
<src path="wifi/java" />
</coverage_target>
<coverage_target name="android.test.runner"
build_path="frameworks/base/test-runner" type="JAVA_LIBRARIES">
<src path="." />
</coverage_target>
<!-- apps -->
<coverage_target name="AlarmClock" build_path="packages/apps/AlarmClock"
type="APPS" />
<coverage_target name="ApiDemos" build_path="development/samples/ApiDemos"
type="APPS" />
<coverage_target name="Browser" build_path="packages/apps/Browser"
type="APPS" />
<coverage_target name="Calculator" build_path="packages/apps/Calculator"
type="APPS" />
<coverage_target name="Calendar" build_path="packages/apps/Calendar"
type="APPS" />
<coverage_target name="Camera" build_path="packages/apps/Camera"
type="APPS" />
<coverage_target name="Contacts" build_path="packages/apps/Contacts"
type="APPS" />
<coverage_target name="Email" build_path="packages/apps/Email"
type="APPS" />
<coverage_target name="Settings" build_path="packages/apps/Settings"
type="APPS" />
<coverage_target name="Phone" build_path="packages/apps/Phone"
type="APPS" />
<coverage_target name="Launcher" build_path="packages/apps/Home"
type="APPS" />
<coverage_target name="IM" build_path="packages/apps/IM" type="APPS" />
<coverage_target name="Mms" build_path="packages/apps/Mms" type="APPS" />
<coverage_target name="Music" build_path="packages/apps/Music"
type="APPS" />
<coverage_target name="VoiceDialer" build_path="packages/apps/VoiceDialer"
type="APPS" />
<!-- content providers -->
<coverage_target name="CalendarProvider"
build_path="packages/providers/calendar" type="APPS" />
<coverage_target name="ContactsProvider"
build_path="packages/providers/ContactsProvider" type="APPS" />
<coverage_target name="GoogleContactsProvider"
build_path="packages/providers/GoogleContactsProvider" type="APPS" />
<coverage_target name="DownloadProvider"
build_path="packages/providers/DownloadProvider" type="APPS" />
<coverage_target name="DrmProvider" build_path="packages/providers/drm"
type="APPS" />
<coverage_target name="GmailProvider"
build_path="partner/google/providers/gmail" type="APPS" />
<coverage_target name="ImProvider"
build_path="packages/providers/ImProvider" type="APPS" />
<coverage_target name="MediaProvider"
build_path="packages/providers/MediaProvider" type="APPS" />
<coverage_target name="SettingsProvider"
build_path="frameworks/base/packages/SettingsProvider" type="APPS" />
<coverage_target name="TelephonyProvider"
build_path="packages/providers/telephony" type="APPS" />
</coverage_targets>

40
testrunner/errors.py Executable file
View File

@@ -0,0 +1,40 @@
#!/usr/bin/python2.4
#
#
# Copyright 2008, 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.
"""Defines common exception classes for this package."""
class WaitForResponseTimedOutError(Exception):
"""We sent a command and had to wait too long for response."""
class DeviceUnresponsiveError(Exception):
"""Device is unresponsive to command."""
class InstrumentationError(Exception):
"""Failed to run instrumentation."""
class AbortError(Exception):
"""Generic exception that indicates a fatal error has occurred and program
execution should be aborted."""
class ParseError(Exception):
"""Raised when xml data to parse has unrecognized format."""

85
testrunner/logger.py Executable file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/python2.4
#
#
# Copyright 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.
"""Simple logging utility. Dumps log messages to stdout, and optionally, to a
log file.
Init(path) must be called to enable logging to a file
"""
import datetime
_LOG_FILE = None
_verbose = False
def Init(log_file_path):
"""Set the path to the log file"""
global _LOG_FILE
_LOG_FILE = log_file_path
print "Using log file: %s" % _LOG_FILE
def GetLogFilePath():
"""Returns the path and name of the Log file"""
global _LOG_FILE
return _LOG_FILE
def Log(new_str):
"""Appends new_str to the end of _LOG_FILE and prints it to stdout.
Args:
# new_str is a string.
new_str: 'some message to log'
"""
msg = _PrependTimeStamp(new_str)
print msg
_WriteLog(msg)
def _WriteLog(msg):
global _LOG_FILE
if _LOG_FILE is not None:
file_handle = file(_LOG_FILE, 'a')
file_handle.write('\n' + str(msg))
file_handle.close()
def _PrependTimeStamp(log_string):
"""Returns the log_string prepended with current timestamp """
return "# %s: %s" % (datetime.datetime.now().strftime("%m/%d/%y %H:%M:%S"),
log_string)
def SilentLog(new_str):
"""Silently log new_str. Unless verbose mode is enabled, will log new_str
only to the log file
Args:
# new_str is a string.
new_str: 'some message to log'
"""
global _verbose
msg = _PrependTimeStamp(new_str)
if _verbose:
print msg
_WriteLog(msg)
def SetVerbose(new_verbose=True):
""" Enable or disable verbose logging"""
global _verbose
_verbose = new_verbose
def main():
pass
if __name__ == '__main__':
main()

117
testrunner/run_command.py Executable file
View File

@@ -0,0 +1,117 @@
#!/usr/bin/python2.4
#
#
# Copyright 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.
# System imports
import os
import signal
import subprocess
import time
import threading
# local imports
import logger
import errors
_abort_on_error = False
def SetAbortOnError(abort=True):
"""Sets behavior of RunCommand to throw AbortError if command process returns
a negative error code"""
global _abort_on_error
_abort_on_error = abort
def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True):
"""Spawns a subprocess to run the given shell command, and checks for
timeout_time. If return_output is True, the output of the command is returned
as a string. Otherwise, output of command directed to stdout """
result = None
while True:
try:
result = RunOnce(cmd, timeout_time=timeout_time,
return_output=return_output)
except errors.WaitForResponseTimedOutError:
if retry_count == 0:
raise
retry_count -= 1
logger.Log("No response for %s, retrying" % cmd)
else:
# Success
return result
def RunOnce(cmd, timeout_time=None, return_output=True):
start_time = time.time()
so = []
pid = []
global _abort_on_error
error_occurred = False
def Run():
if return_output:
output_dest = subprocess.PIPE
else:
# None means direct to stdout
output_dest = None
pipe = subprocess.Popen(
cmd,
executable='/bin/bash',
stdout=output_dest,
stderr=subprocess.STDOUT,
shell=True)
pid.append(pipe.pid)
try:
output = pipe.communicate()[0]
if output is not None and len(output) > 0:
so.append(output)
except OSError, e:
logger.SilentLog("failed to retrieve stdout from: %s" % cmd)
logger.Log(e)
so.append("ERROR")
error_occurred = True
if pipe.returncode < 0:
logger.SilentLog("Error: %s was terminated by signal %d" %(cmd,
pipe.returncode))
error_occurred = True
t = threading.Thread(target=Run)
t.start()
break_loop = False
while not break_loop:
if not t.isAlive():
break_loop = True
# Check the timeout
if (not break_loop and timeout_time is not None
and time.time() > start_time + timeout_time):
try:
os.kill(pid[0], signal.SIGKILL)
except OSError:
# process already dead. No action required.
pass
logger.SilentLog("about to raise a timeout for: %s" % cmd)
raise errors.WaitForResponseTimedOutError
if not break_loop:
time.sleep(0.1)
t.join()
if _abort_on_error and error_occurred:
raise errors.AbortError
return "".join(so)

Some files were not shown because too many files have changed in this diff Show More