Merge commit 'remotes/korg/cupcake' into cupcake_to_master
This commit is contained in:
11
apps/CustomLocale/Android.mk
Normal file
11
apps/CustomLocale/Android.mk
Normal 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)
|
||||||
37
apps/CustomLocale/AndroidManifest.xml
Normal file
37
apps/CustomLocale/AndroidManifest.xml
Normal 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>
|
||||||
BIN
apps/CustomLocale/res/drawable/icon.png
Normal file
BIN
apps/CustomLocale/res/drawable/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
35
apps/CustomLocale/res/layout/list_item.xml
Normal file
35
apps/CustomLocale/res/layout/list_item.xml
Normal 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>
|
||||||
62
apps/CustomLocale/res/layout/main.xml
Normal file
62
apps/CustomLocale/res/layout/main.xml
Normal 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>
|
||||||
49
apps/CustomLocale/res/layout/new_locale.xml
Normal file
49
apps/CustomLocale/res/layout/new_locale.xml
Normal 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>
|
||||||
25
apps/CustomLocale/res/values-fr/strings.xml
Normal file
25
apps/CustomLocale/res/values-fr/strings.xml
Normal 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>
|
||||||
18
apps/CustomLocale/res/values/colors.xml
Normal file
18
apps/CustomLocale/res/values/colors.xml
Normal 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>
|
||||||
26
apps/CustomLocale/res/values/strings.xml
Normal file
26
apps/CustomLocale/res/values/strings.xml
Normal 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>
|
||||||
25
apps/CustomLocale/res/values/styles.xml
Normal file
25
apps/CustomLocale/res/values/styles.xml
Normal 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>
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
|
||||||
21
apps/Fallback/res/values-ko/strings.xml
Normal file
21
apps/Fallback/res/values-ko/strings.xml
Normal 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>
|
||||||
21
apps/Fallback/res/values-nb/strings.xml
Normal file
21
apps/Fallback/res/values-nb/strings.xml
Normal 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>
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
10
data/etc/vold.conf
Normal 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
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
7
emulator/keymaps/AVRCP.kl
Normal file
7
emulator/keymaps/AVRCP.kl
Normal 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
|
||||||
|
|
||||||
@@ -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.
Binary file not shown.
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"/>
|
||||||
|
|||||||
23
pdk/Pdk.mk
23
pdk/Pdk.mk
@@ -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:
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.android.samples.tests">
|
package="com.example.android.apis.tests">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
|
<!-- 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. -->
|
||||||
|
<application>
|
||||||
|
<uses-library android:name="android.test.runner" />
|
||||||
|
</application>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
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"
|
||||||
-->
|
-->
|
||||||
<instrumentation android:name="android.test.InstrumentationTestRunner"
|
<instrumentation android:name="android.test.InstrumentationTestRunner"
|
||||||
android:targetPackage="com.android.samples"
|
android:targetPackage="com.example.android.apis"
|
||||||
android:label="Tests for Api Demos."/>
|
android:label="Tests for Api Demos."/>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
</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">
|
||||||
<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
|
|
||||||
|
|
||||||
<instrumentation android:name="android.tests.FrameworkInstrumentationTestRunner"
|
<instrumentation android:name="android.tests.FrameworkInstrumentationTestRunner"
|
||||||
android:targetPackage="com.google.android.frameworktest"
|
android:targetPackage="com.google.android.frameworktest"
|
||||||
android:label="framework instrumentation test runner" />
|
android:label="framework instrumentation test runner" />
|
||||||
|
|||||||
19
pdk/docs/templates/footer.cs
vendored
Executable file
19
pdk/docs/templates/footer.cs
vendored
Executable 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
37
pdk/docs/templates/head_tag.cs
vendored
Executable 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
3
pdk/docs/templates/header.cs
vendored
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
<?cs call:custom_masthead() ?>
|
||||||
|
<?cs call:custom_left_nav() ?>
|
||||||
|
|
||||||
8
pdk/docs/templates/index.cs
vendored
Executable file
8
pdk/docs/templates/index.cs
vendored
Executable 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
11
pdk/docs/templates/trailer.cs
vendored
Executable 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
11
pdk/hosting/app.yaml
Normal 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
44
pdk/hosting/pdk.py
Normal 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.
|
||||||
741
pdk/ndk/Android_NDK_README.html
Normal file
741
pdk/ndk/Android_NDK_README.html
Normal 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 build is routinely tested on recent versions of Ubuntu (6.06 and later), 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>. </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"> </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">$ </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 reason why Android cannot be built on non-Ubuntu systems<span style=FONT-WEIGHT:normal><font size=2>. In general you will need:</font></span>
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Git 1.5.4 or newer. You can find it at <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 { hdiutil attach ~/android.dmg
|
||||||
|
-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. 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>
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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.
|
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 -->
|
||||||
<!-- ************************************* -->
|
<!-- ************************************* -->
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
42
samples/ApiDemos/res/layout/appwidget_configure.xml
Normal file
42
samples/ApiDemos/res/layout/appwidget_configure.xml
Normal 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>
|
||||||
23
samples/ApiDemos/res/layout/appwidget_provider.xml
Normal file
23
samples/ApiDemos/res/layout/appwidget_provider.xml
Normal 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"
|
||||||
|
/>
|
||||||
|
|
||||||
38
samples/ApiDemos/res/layout/reorder_four.xml
Normal file
38
samples/ApiDemos/res/layout/reorder_four.xml
Normal 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>
|
||||||
38
samples/ApiDemos/res/layout/reorder_on_launch.xml
Normal file
38
samples/ApiDemos/res/layout/reorder_on_launch.xml
Normal 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>
|
||||||
38
samples/ApiDemos/res/layout/reorder_three.xml
Normal file
38
samples/ApiDemos/res/layout/reorder_three.xml
Normal 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>
|
||||||
38
samples/ApiDemos/res/layout/reorder_two.xml
Normal file
38
samples/ApiDemos/res/layout/reorder_two.xml
Normal 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>
|
||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
27
samples/ApiDemos/res/xml/appwidget_provider.xml
Normal file
27
samples/ApiDemos/res/xml/appwidget_provider.xml
Normal 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. -->
|
||||||
|
|
||||||
@@ -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=" ? "
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
BIN
samples/SoftKeyboard/res/drawable/sym_keyboard_search.png
Executable file
BIN
samples/SoftKeyboard/res/drawable/sym_keyboard_search.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
@@ -19,5 +19,5 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<dimen name="key_height">46px</dimen>
|
<dimen name="key_height">46dip</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -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>
|
||||||
@@ -25,9 +25,7 @@
|
|||||||
<string name="word_separators">\u0020.,;:!?\n()[]*&@{}/<>_+=|"</string>
|
<string name="word_separators">\u0020.,;:!?\n()[]*&@{}/<>_+=|"</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>
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
347
testrunner/adb_interface.py
Executable 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
|
||||||
178
testrunner/am_instrument_parser.py
Executable file
178
testrunner/am_instrument_parser.py
Executable 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
312
testrunner/coverage.py
Executable 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()
|
||||||
131
testrunner/coverage_targets.py
Normal file
131
testrunner/coverage_targets.py
Normal 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
|
||||||
111
testrunner/coverage_targets.xml
Normal file
111
testrunner/coverage_targets.xml
Normal 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
40
testrunner/errors.py
Executable 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
85
testrunner/logger.py
Executable 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
117
testrunner/run_command.py
Executable 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
Reference in New Issue
Block a user