auto import from //depot/cupcake/@132589

This commit is contained in:
The Android Open Source Project
2009-03-03 14:03:58 -08:00
parent b8747bc7b1
commit d2f2b1d7b7
91 changed files with 829 additions and 3654 deletions

View File

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

View File

@@ -1,37 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0" package="com.android.customlocale">
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
<activity
android:label="@string/app_name" android:name="CustomLocaleActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="NewLocaleDialog"
android:theme="@android:style/Theme.Dialog" />
</application>
<uses-sdk android:minSdkVersion="3" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
</manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dip">
<TextView
android:id="@+id/locale_code"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearanceLarge"
android:layout_weight="1"
android:text="@string/locale_default" />
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/locale_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearance"
android:layout_weight="1" />
</LinearLayout>

View File

@@ -1,62 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:text="@string/header_current_locale"
android:textAppearance="@style/TextAppearance.header"
android:gravity="center_horizontal"
android:background="@color/header_background" />
<TextView
android:id="@+id/current_locale"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:padding="5dip" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:text="@string/header_locale_list"
android:textAppearance="@style/TextAppearance.header"
android:gravity="center_horizontal"
android:background="@color/header_background" />
<ListView
android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:padding="8dip" />
<TextView
android:id="@id/android:empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="@string/no_data_label" />
<Button
android:id="@+id/new_locale"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:paddingLeft="8dip"
android:paddingRight="8dip"
android:text="@string/add_new_locale_button" />
</LinearLayout>

View File

@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="8dip"
android:paddingRight="8dip">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/new_locale_label" />
<EditText
android:id="@+id/value"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/locale_default" android:inputType="text"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/add"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/add_button" android:layout_gravity="center_vertical"/>
<Button
android:id="@+id/add_and_select"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/add_select_button" android:layout_gravity="center_vertical"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="app_name">Locales Personalisées</string>
<string name="add_new_locale_button">Ajouter une nouvelle locale</string>
<string name="new_locale_label">Code de la nouvelle locale:</string>
<string name="add_button">Ajouter</string>
<string name="no_data_label">Aucune locale</string>
<string name="header_current_locale">Locale courrante</string>
<string name="header_locale_list">Liste des locales</string>
<string name="add_select_button">Ajouter et sélectionner</string>
</resources>

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<color name="header_background">#888</color>
</resources>

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="app_name">Custom Locale</string>
<string name="locale_default">ex_EX</string>
<string name="add_new_locale_button">Add New Locale</string>
<string name="new_locale_label">New locale code:</string>
<string name="add_button">Add</string>
<string name="no_data_label">No data</string>
<string name="header_current_locale">Current Locale</string>
<string name="header_locale_list">Locale List</string>
<string name="add_select_button">Add and Select</string>
</resources>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<style name="TextAppearance"
parent="android:TextAppearance" />
<style name="TextAppearance.header">
<item name="android:textSize">14sp</item>
<item name="android:textStyle">bold</item>
</style>
</resources>

View File

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

View File

@@ -1,93 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.customlocale;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
/**
* Dialog to ask the user for a new locale. <p/> Returns the locale code (e.g.
* "en_US") via an intent with a "locale" extra string and a "select" extra
* boolean.
*/
public class NewLocaleDialog extends Activity
implements View.OnClickListener, View.OnKeyListener {
public static final String INTENT_EXTRA_LOCALE = "locale";
public static final String INTENT_EXTRA_SELECT = "select";
private static final String TAG = "NewLocale";
private static final boolean DEBUG = true;
private Button mButtonAdd;
private Button mButtonAddSelect;
private EditText mEditText;
private boolean mWasEmpty;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.new_locale);
mEditText = (EditText) findViewById(R.id.value);
mWasEmpty = true;
mButtonAdd = (Button) findViewById(R.id.add);
mButtonAdd.setOnClickListener(this);
mButtonAdd.setEnabled(false);
mButtonAddSelect = (Button) findViewById(R.id.add_and_select);
mButtonAddSelect.setOnClickListener(this);
mButtonAddSelect.setEnabled(false);
mEditText.setOnKeyListener(this);
}
public void onClick(View v) {
String locale = mEditText.getText().toString();
boolean select = v == mButtonAddSelect;
if (DEBUG) {
Log.d(TAG, "New Locale: " + locale + (select ? " + select" : ""));
}
Intent data = new Intent(NewLocaleDialog.this, NewLocaleDialog.class);
data.putExtra(INTENT_EXTRA_LOCALE, locale);
data.putExtra(INTENT_EXTRA_SELECT, select);
setResult(RESULT_OK, data);
finish();
}
public boolean onKey(View v, int keyCode, KeyEvent event) {
boolean isEmpty = TextUtils.isEmpty(mEditText.getText());
if (isEmpty != mWasEmpty) {
mWasEmpty = isEmpty;
mButtonAdd.setEnabled(!isEmpty);
mButtonAddSelect.setEnabled(!isEmpty);
}
return false;
}
}

View File

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

View File

@@ -20,17 +20,6 @@
<resources>
<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="title_window_animations">Window animations</string>
@@ -59,7 +48,7 @@
<string name="title_accelerometer">Display rotation</string>
<string name="summary_on_accelerometer">Display rotates from orientation</string>
<string name="summary_off_accelerometer">Display rotates from orientation</string>
<string name="summary_off_accelerometer">Display rotates when lid is open</string>
<string name="applications_title">Applications</string>

View File

@@ -18,35 +18,6 @@
-->
<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
android:title="@string/general_title">

View File

@@ -19,11 +19,7 @@ package com.android.spare_parts;
import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.Intent;
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.res.Configuration;
import android.os.RemoteException;
@@ -32,7 +28,6 @@ import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -40,17 +35,11 @@ import android.os.Bundle;
import android.util.Log;
import android.view.IWindowManager;
import java.util.List;
public class SpareParts extends PreferenceActivity
implements Preference.OnPreferenceChangeListener,
SharedPreferences.OnSharedPreferenceChangeListener {
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 TRANSITION_ANIMATIONS_PREF = "transition_animations";
private static final String FANCY_IME_ANIMATIONS_PREF = "fancy_ime_animations";
@@ -73,41 +62,6 @@ public class SpareParts extends PreferenceActivity
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
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -130,15 +84,7 @@ public class SpareParts extends PreferenceActivity
mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
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);
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
private void updateToggles() {

View File

@@ -66,7 +66,6 @@ development/samples/NotePad platforms/${PLATFORM_NAME}/samples/NotePad
development/samples/ApiDemos platforms/${PLATFORM_NAME}/samples/ApiDemos
development/samples/SkeletonApp platforms/${PLATFORM_NAME}/samples/SkeletonApp
development/samples/Snake platforms/${PLATFORM_NAME}/samples/Snake
development/samples/SoftKeyboard platforms/${PLATFORM_NAME}/samples/SoftKeyboard
# dx
bin/dx platforms/${PLATFORM_NAME}/tools/dx

View File

@@ -146,11 +146,6 @@ function package() {
echo "Done"
echo
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

View File

@@ -1,19 +0,0 @@
<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 -->

View File

@@ -1,37 +0,0 @@
<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>

View File

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

View File

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

View File

@@ -1,11 +0,0 @@
</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>

View File

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

View File

@@ -21,26 +21,28 @@ import android.app.ActivityManager;
import android.app.SearchManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
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.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.ColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.util.Xml;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -55,19 +57,14 @@ import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.TextView;
import android.net.Uri;
import java.io.IOException;
import java.io.FileReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
public class Home extends Activity {
/**
* Tag used for logging errors.
@@ -79,13 +76,6 @@ public class Home extends Activity {
*/
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
private static final int MENU_WALLPAPER_SETTINGS = Menu.FIRST + 1;
private static final int MENU_SEARCH = MENU_WALLPAPER_SETTINGS + 1;
@@ -100,8 +90,11 @@ public class Home extends Activity {
private static ArrayList<ApplicationInfo> mApplications;
private static LinkedList<ApplicationInfo> mFavorites;
private Handler mHandler = new Handler();
private final BroadcastReceiver mWallpaperReceiver = new WallpaperIntentReceiver();
private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver();
private final ContentObserver mObserver = new FavoritesChangeObserver();
private GridView mGrid;
@@ -127,6 +120,7 @@ public class Home extends Activity {
setContentView(R.layout.home);
registerIntentReceivers();
registerContentObservers();
setDefaultWallpaper();
@@ -162,6 +156,7 @@ public class Home extends Activity {
mApplications.get(i).icon.setCallback(null);
}
getContentResolver().unregisterContentObserver(mObserver);
unregisterReceiver(mWallpaperReceiver);
unregisterReceiver(mApplicationsReceiver);
}
@@ -203,6 +198,16 @@ public class Home extends Activity {
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.
*/
@@ -242,7 +247,7 @@ public class Home extends Activity {
Log.e(LOG_TAG, "Failed to clear wallpaper " + e);
}
} else {
getWindow().setBackgroundDrawable(new ClippedDrawable(wallpaper));
getWindow().setBackgroundDrawable(wallpaper);
}
mWallpaperChecked = true;
}
@@ -254,17 +259,18 @@ public class Home extends Activity {
*/
private void bindFavorites(boolean isLaunching) {
if (!isLaunching || mFavorites == null) {
final Cursor c = getContentResolver().query(Uri.parse("content://" +
android.provider.Settings.AUTHORITY + "/favorites?notify=true"),
null, null, null, "cellX");
FileReader favReader;
final int intentIndex = c.getColumnIndexOrThrow("intent");
final int titleIndex = c.getColumnIndexOrThrow("title");
final int typeIndex = c.getColumnIndexOrThrow("itemType");
// Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
final File favFile = new File(Environment.getRootDirectory(), DEFAULT_FAVORITES_PATH);
try {
favReader = new FileReader(favFile);
} catch (FileNotFoundException e) {
Log.e(LOG_TAG, "Couldn't find or open favorites file " + favFile);
return;
}
final PackageManager manager = getPackageManager();
ApplicationInfo info;
String intentDescription;
if (mFavorites == null) {
mFavorites = new LinkedList<ApplicationInfo>();
@@ -272,77 +278,38 @@ public class Home extends Activity {
mFavorites.clear();
}
final Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
while (c.moveToNext()) {
final int itemType = c.getInt(typeIndex);
final PackageManager packageManager = getPackageManager();
if (itemType == 0 || // 0 == application
itemType == 1) { // 1 == shortcut
try {
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(favReader);
beginDocument(parser, TAG_FAVORITES);
ApplicationInfo info;
while (true) {
nextElement(parser);
String name = parser.getName();
if (!TAG_FAVORITE.equals(name)) {
break;
intentDescription = c.getString(intentIndex);
if (intentDescription == null) {
continue;
}
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);
Intent intent;
try {
intent = Intent.getIntent(intentDescription);
} catch (java.net.URISyntaxException e) {
continue;
}
info = getApplicationInfo(manager, intent);
if (info != null) {
info.title = c.getString(titleIndex);
info.intent = intent;
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);
}
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
* of recents depends on how many favorites are present.
@@ -394,6 +361,14 @@ public class Home extends Activity {
return info;
}
/**
* When the notification that favorites have changed is received, requests
* a favorites list refresh.
*/
private void onFavoritesChanged() {
bindFavorites(false);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
@@ -555,7 +530,7 @@ public class Home extends Activity {
private class WallpaperIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
getWindow().setBackgroundDrawable(new ClippedDrawable(getWallpaper()));
getWindow().setBackgroundDrawable(getWallpaper());
}
}
@@ -572,6 +547,20 @@ 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.
*/
@@ -591,12 +580,13 @@ public class Home extends Activity {
convertView = inflater.inflate(R.layout.application, parent, false);
}
//final ImageView imageView = (ImageView) convertView.findViewById(R.id.icon);
Drawable icon = info.icon;
if (!info.filtered) {
//final Resources resources = getContext().getResources();
int width = 42;//(int) resources.getDimension(android.R.dimen.app_icon_size);
int height = 42;//(int) resources.getDimension(android.R.dimen.app_icon_size);
final Resources resources = getContext().getResources();
int width = (int) resources.getDimension(android.R.dimen.app_icon_size);
int height = (int) resources.getDimension(android.R.dimen.app_icon_size);
final int iconWidth = icon.getIntrinsicWidth();
final int iconHeight = icon.getIntrinsicHeight();
@@ -697,47 +687,4 @@ public class Home extends Activity {
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();
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

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

View File

@@ -20,14 +20,9 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.Keyboard.Key;
import android.inputmethodservice.Keyboard.Row;
import android.view.inputmethod.EditorInfo;
public class LatinKeyboard extends Keyboard {
private Key mEnterKey;
public LatinKeyboard(Context context, int xmlLayoutResId) {
super(context, xmlLayoutResId);
}
@@ -40,49 +35,7 @@ public class LatinKeyboard extends Keyboard {
@Override
protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
XmlResourceParser 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;
}
return new LatinKey(res, parent, x, y, parser);
}
static class LatinKey extends Keyboard.Key {

View File

@@ -65,11 +65,11 @@ public class SoftKeyboard extends InputMethodService
private long mLastShiftTime;
private long mMetaState;
private LatinKeyboard mSymbolsKeyboard;
private LatinKeyboard mSymbolsShiftedKeyboard;
private LatinKeyboard mQwertyKeyboard;
private Keyboard mSymbolsKeyboard;
private Keyboard mSymbolsShiftedKeyboard;
private Keyboard mQwertyKeyboard;
private LatinKeyboard mCurKeyboard;
private Keyboard mCurKeyboard;
private String mWordSeparators;
@@ -208,10 +208,6 @@ public class SoftKeyboard extends InputMethodService
// keyboard with no special features.
mCurKeyboard = mQwertyKeyboard;
}
// Update the label on the enter key, depending on what the application
// says it will do.
mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions);
}
/**
@@ -508,18 +504,6 @@ 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
* text. This will need to be filled in by however you are determining

View File

@@ -1,208 +0,0 @@
<?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.
-->
<!--
This file contains standard test definitions for the Android platform
Tests are defined by <test> tags with the following attributes
name package [class runner build_path coverage_target continuous]
Where:
name: Self-descriptive name used to uniquely identify the test
build_path: File system path, relative to Android build root, to this package's
Android.mk file. If omitted, build/sync step for this test will be skipped
package: Android application package that contains the tests
class: Optional. Fully qualified Java test class to run.
runner: Fully qualified InstrumentationTestRunner to execute. If omitted,
will default to android.test.InstrumentationTestRunner
coverage_target: Build name of Android package this test targets - these targets
are defined in the coverage_targets.xml file. Used as basis for code
coverage metrics. If omitted, code coverage will not be supported for this
test
continuous: Optional boolean. Default is false. Set to true if tests are known
to be reliable, and should be included in a continuous test system. false if
they are under development.
These attributes map to the following commands:
(if class is defined)
adb shell am instrument -w <package>/<runner>
(else)
adb shell am instrument -w -e class <class> <package>/<runner>
-->
<test-definitions version="1">
<!-- system-wide tests -->
<test name="framework"
build_path="frameworks/base/tests/FrameworkTest"
package="com.android.frameworktest.tests"
class="com.android.frameworktest.AllTests"
coverage_target="framework"
continuous="true" />
<test name="android"
build_path="frameworks/base/tests/AndroidTests"
package="com.android.unit_tests"
class="com.android.unit_tests.AndroidTests"
coverage_target="framework"
continuous="true" />
<test name="smoke"
build_path="frameworks/base/tests/SmokeTest"
package="com.android.smoketest.tests"
coverage_target="framework"
continuous="true" />
<test name="core"
build_path="frameworks/base/tests/CoreTests"
package="android.core"
class="android.core.CoreTests"
coverage_target="framework"
continuous="true" />
<test name="libcore"
build_path="frameworks/base/tests/CoreTests"
package="android.core"
class="android.core.JavaTests"
coverage_target="framework" />
<test name="apidemos"
build_path="development/samples/ApiDemos"
package="com.example.android.apis.tests"
coverage_target="ApiDemos"
continuous="true" />
<!-- targeted framework tests -->
<test name="heap"
build_path="frameworks/base/tests/AndroidTests"
package="com.android.unit_tests"
class="com.android.unit_tests.HeapTest"
coverage_target="framework" />
<test name="activity"
build_path="frameworks/base/tests/AndroidTests"
package="com.android.unit_tests"
class="com.android.unit_tests.activity.ActivityTests"
coverage_target="framework" />
<!-- obsolete?
<test name="deadlock"
build_path="frameworks/base/tests/Deadlock"
package="com.android.deadlock.tests"
coverage_target="framework" />
-->
<test name="tablemerger"
build_path="frameworks/base/tests/FrameworkTest"
package="com.android.frameworktest.tests"
class="android.content.AbstractTableMergerTest"
coverage_target="framework" />
<!-- selected app tests -->
<test name="browser"
build_path="packages/apps/Browser"
package="com.android.browser"
runner=".BrowserTestRunner"
coverage_target="Browser" />
<test name="browserfunc"
build_path="packages/apps/Browser"
package="com.android.browser"
runner=".BrowserFunctionalTestRunner"
coverage_target="Browser" />
<test name="calendar"
build_path="packages/apps/Calendar/tests"
package="com.android.calendar.tests"
coverage_target="Calendar"
continuous="true" />
<test name="calprov"
build_path="packages/providers/CalendarProvider/tests"
package="com.android.providers.calendar.tests"
coverage_target="CalendarProvider"
continuous="true" />
<test name="camera"
build_path="packages/apps/Camera/tests"
package="com.android.cameratests"
runner="CameraInstrumentationTestRunner"
coverage_target="Camera" />
<test name="contactsprov"
build_path="packages/providers/GoogleContactsProvider/tests"
package="com.android.providers.contactstests"
coverage_target="ContactsProvider" />
<test name="email"
build_path="packages/apps/Email"
package="com.android.email.tests"
coverage_target="Email"
continuous="true" />
<test name="emailsmall"
build_path="packages/apps/Email"
package="com.android.email.tests"
class="com.android.email.SmallTests"
coverage_target="Email" />
<test name="media"
build_path="frameworks/base/media/tests/MediaFrameworkTest"
package="com.android.mediaframeworktest"
runner=".MediaFrameworkTestRunner"
coverage_target="framework"
continuous="true" />
<test name="mediaunit"
build_path="frameworks/base/media/tests/MediaFrameworkTest"
package="com.android.mediaframeworktest"
runner=".MediaFrameworkUnitTestRunner"
coverage_target="framework" />
<!-- obsolete?
<test name="mediaprov"
build_path="tests/MediaProvider"
package="com.android.mediaprovidertests"
runner=".MediaProviderTestsInstrumentation"
coverage_target="MediaProvider" />
-->
<test name="mms"
build_path="packages/apps/Mms"
package="com.android.mms.tests"
runner="com.android.mms.ui.MMSInstrumentationTestRunner"
coverage_target="Mms" />
<test name="mmslaunch"
build_path="packages/apps/Mms"
package="com.android.mms.tests"
runner="com.android.mms.SmsLaunchPerformance"
coverage_target="Mms" />
<!-- obsolete?
<test name="ringtone"
build_path="tests/RingtoneSettings"
package="com.android.ringtonesettingstests"
runner=".RingtoneSettingsInstrumentationTestRunner"
coverage_target="Settings" />
-->
</test-definitions>

View File

@@ -20,9 +20,9 @@ rem Set up prog to be the path of this script, including following symlinks,
rem and set up progdir to be the fully-qualified pathname of its directory.
set prog=%~f0
rem Change current directory and drive to where the script is, to avoid
rem issues with directories containing whitespaces.
cd /d %~dp0
rem Change current directory to where ddms is, to avoid issues with directories
rem containing whitespaces.
cd %~dp0
set jarfile=apkbuilder.jar
set frameworkdir=

View File

@@ -20,9 +20,9 @@ rem Set up prog to be the path of this script, including following symlinks,
rem and set up progdir to be the fully-qualified pathname of its directory.
set prog=%~f0
rem Change current directory and drive to where the script is, to avoid
rem issues with directories containing whitespaces.
cd /d %~dp0
rem Change current directory to where ddms is, to avoid issues with directories
rem containing whitespaces.
cd %~dp0
set jarfile=ddms.jar
set frameworkdir=

View File

@@ -94,7 +94,7 @@ public class Client {
* is only used for data generated within Client.
*/
private static final int INITIAL_BUF_SIZE = 2*1024;
private static final int MAX_BUF_SIZE = 200*1024*1024;
private static final int MAX_BUF_SIZE = 2*1024*1024;
private ByteBuffer mReadBuffer;
private static final int WRITE_BUF_SIZE = 256;

View File

@@ -251,15 +251,6 @@ public final class Device implements IDevice {
AdbHelper.runEventLogService(AndroidDebugBridge.sSocketAddr, this, receiver);
}
/*
* (non-Javadoc)
* @see com.android.ddmlib.IDevice#runLogService(com.android.ddmlib.log.LogReceiver)
*/
public void runLogService(String logname,
LogReceiver receiver) throws IOException {
AdbHelper.runLogService(AndroidDebugBridge.sSocketAddr, this, logname, receiver);
}
/*
* (non-Javadoc)
* @see com.android.ddmlib.IDevice#createForward(int, int)

View File

@@ -151,14 +151,6 @@ public interface IDevice {
*/
public void runEventLogService(LogReceiver receiver) throws IOException;
/**
* Runs the log service for the given log and outputs the log to the {@link LogReceiver}.
* @param logname the logname of the log to read from.
* @param receiver the receiver to receive the event log entries.
* @throws IOException
*/
public void runLogService(String logname, LogReceiver receiver) throws IOException;
/**
* Creates a port forwarding between a local and a remote port.
* @param localPort the local port to forward

View File

@@ -17,69 +17,56 @@
package com.android.ddmlib.testrunner;
/**
* Receives event notifications during instrumentation test runs.
* Patterned after {@link junit.runner.TestRunListener}.
* Listener for instrumentation test runs
*
* Modeled after junit.runner.TestRunListener
*/
public interface ITestRunListener {
public static final int STATUS_ERROR = 1;
public static final int STATUS_FAILURE = 2;
/**
* Types of test failures.
*/
enum TestFailure {
/** Test failed due to unanticipated uncaught exception. */
ERROR,
/** Test failed due to a false assertion. */
FAILURE
}
/**
* Reports the start of a test run.
*
* @param testCount total number of tests in test run
*/
* Reports the start of a test run
* @param testCount - total number of tests in test run
* */
public void testRunStarted(int testCount);
/**
* Reports end of test run.
*
* @param elapsedTime device reported elapsed time, in milliseconds
* Reports end of test run
* @param elapsedTime - device reported elapsed time, in milliseconds
*/
public void testRunEnded(long elapsedTime);
/**
* Reports test run stopped before completion.
*
* @param elapsedTime device reported elapsed time, in milliseconds
* Reports test run stopped before completion
* @param elapsedTime - device reported elapsed time, in milliseconds
*/
public void testRunStopped(long elapsedTime);
/**
* Reports the start of an individual test case.
*
* @param test identifies the test
* Reports the start of an individual test case
*/
public void testStarted(TestIdentifier test);
public void testStarted(String className, String testName);
/**
* Reports the execution end of an individual test case.
* If {@link #testFailed} was not invoked, this test passed.
*
* @param test identifies the test
* Reports the execution end of an individual test case
* If no testFailed has been reported, this is a passed test
*/
public void testEnded(TestIdentifier test);
public void testEnded(String className, String testName);
/**
* Reports the failure of a individual test case.
* Will be called between testStarted and testEnded.
* Reports the failure of a individual test case
* Will be called between testStarted and testEnded
*
* @param status failure type
* @param test identifies the test
* @param trace stack trace of failure
* @param status - one of STATUS_ERROR, STATUS_FAILURE
* @param className - name of test class
* @param testName - name of test method
* @param trace - stack trace of failure
*/
public void testFailed(TestFailure status, TestIdentifier test, String trace);
public void testFailed(int status, String className, String testName, String trace);
/**
* Reports test run failed to execute due to a fatal error.
* Reports test run failed to execute due to a fatal error
*/
public void testRunFailed(String errorMessage);
}

View File

@@ -20,21 +20,24 @@ import com.android.ddmlib.IShellOutputReceiver;
import com.android.ddmlib.Log;
import com.android.ddmlib.MultiLineReceiver;
import java.util.Hashtable;
import java.util.Map;
/**
* Parses the 'raw output mode' results of an instrumentation test run from shell and informs a
* ITestRunListener of the results.
* Parses the 'raw output mode' results of an instrument test run from shell, and informs a
* ITestRunListener of the results
*
* <p>Expects the following output:
* Expects the following output:
*
* <p>If fatal error occurred when attempted to run the tests:
* <pre> INSTRUMENTATION_FAILED: </pre>
* If fatal error occurred when attempted to run the tests:
* <i> INSTRUMENTATION_FAILED: </i>
*
* <p>Otherwise, expect a series of test results, each one containing a set of status key/value
* Otherwise, expect a series of test results, each one containing a set of status key/value
* pairs, delimited by a start(1)/pass(0)/fail(-2)/error(-1) status code result. At end of test
* run, expects that the elapsed test time in seconds will be displayed
*
* <p>For example:
* <pre>
* i.e.
* <i>
* INSTRUMENTATION_STATUS_CODE: 1
* INSTRUMENTATION_STATUS: class=com.foo.FooTest
* INSTRUMENTATION_STATUS: test=testFoo
@@ -45,85 +48,64 @@ import com.android.ddmlib.MultiLineReceiver;
* ...
*
* Time: X
* </pre>
* <p>Note that the "value" portion of the key-value pair may wrap over several text lines
* </i>
*
* Note that the "value" portion of the key-value pair may wrap over several text lines
*/
public class InstrumentationResultParser extends MultiLineReceiver {
/** Relevant test status keys. */
private static class StatusKeys {
private static final String TEST = "test";
private static final String CLASS = "class";
private static final String STACK = "stack";
private static final String NUMTESTS = "numtests";
}
// relevant test status keys
private static final String CODE_KEY = "code";
private static final String TEST_KEY = "test";
private static final String CLASS_KEY = "class";
private static final String STACK_KEY = "stack";
private static final String NUMTESTS_KEY = "numtests";
/** Test result status codes. */
private static class StatusCodes {
private static final int FAILURE = -2;
private static final int START = 1;
private static final int ERROR = -1;
private static final int OK = 0;
}
// test result status codes
private static final int FAILURE_STATUS_CODE = -2;
private static final int START_STATUS_CODE = 1;
private static final int ERROR_STATUS_CODE = -1;
private static final int OK_STATUS_CODE = 0;
/** Prefixes used to identify output. */
private static class Prefixes {
private static final String STATUS = "INSTRUMENTATION_STATUS: ";
private static final String STATUS_CODE = "INSTRUMENTATION_STATUS_CODE: ";
// recognized output patterns
private static final String STATUS_PREFIX = "INSTRUMENTATION_STATUS: ";
private static final String STATUS_PREFIX_CODE = "INSTRUMENTATION_STATUS_CODE: ";
private static final String STATUS_FAILED = "INSTRUMENTATION_FAILED: ";
private static final String TIME_REPORT = "Time: ";
}
private final ITestRunListener mTestListener;
/**
* Test result data
*/
private static class TestResult {
private Integer mCode = null;
private String mTestName = null;
private String mTestClass = null;
private String mStackTrace = null;
private Integer mNumTests = null;
/** Returns true if all expected values have been parsed */
boolean isComplete() {
return mCode != null && mTestName != null && mTestClass != null;
}
}
/** Stores the status values for the test result currently being parsed */
private TestResult mCurrentTestResult = null;
/** Stores the current "key" portion of the status key-value being parsed. */
private String mCurrentKey = null;
/** Stores the current "value" portion of the status key-value being parsed. */
private StringBuilder mCurrentValue = null;
/** True if start of test has already been reported to listener. */
private boolean mTestStartReported = false;
/** The elapsed time of the test run, in milliseconds. */
private long mTestTime = 0;
/** True if current test run has been canceled by user. */
private boolean mIsCancelled = false;
/** key-value map for current test */
private Map<String, String> mStatusValues;
/** stores the current "key" portion of the status key-value being parsed */
private String mCurrentKey;
/** stores the current "value" portion of the status key-value being parsed */
private StringBuilder mCurrentValue;
/** true if start of test has already been reported to listener */
private boolean mTestStartReported;
/** the elapsed time of the test run, in ms */
private long mTestTime;
/** true if current test run has been canceled by user */
private boolean mIsCancelled;
private static final String LOG_TAG = "InstrumentationResultParser";
/**
* Creates the InstrumentationResultParser.
*
* @param listener informed of test results as the tests are executing
* Creates the InstrumentationResultParser
* @param listener - listener to report results to. will be informed of test results as the
* tests are executing
*/
public InstrumentationResultParser(ITestRunListener listener) {
mStatusValues = new Hashtable<String, String>();
mCurrentKey = null;
setTrimLine(false);
mTestListener = listener;
mTestStartReported = false;
mTestTime = 0;
mIsCancelled = false;
}
/**
* Processes the instrumentation test output from shell.
*
* Processes the instrumentation test output from shell
* @see MultiLineReceiver#processNewLines
*/
@Override
@@ -134,37 +116,31 @@ public class InstrumentationResultParser extends MultiLineReceiver {
}
/**
* Parse an individual output line. Expects a line that is one of:
* <ul>
* <li>
* The start of a new status line (starts with Prefixes.STATUS or Prefixes.STATUS_CODE),
* Parse an individual output line. Expects a line that either is:
* a) the start of a new status line (ie. starts with STATUS_PREFIX or STATUS_PREFIX_CODE),
* and thus there is a new key=value pair to parse, and the previous key-value pair is
* finished.
* </li>
* <li>
* A continuation of the previous status (the "value" portion of the key has wrapped
* to the next line).
* </li>
* <li> A line reporting a fatal error in the test run (Prefixes.STATUS_FAILED) </li>
* <li> A line reporting the total elapsed time of the test run. (Prefixes.TIME_REPORT) </li>
* </ul>
* finished
* b) a continuation of the previous status (ie the "value" portion of the key has wrapped
* to the next line.
* c) a line reporting a fatal error in the test run (STATUS_FAILED)
* d) a line reporting the total elapsed time of the test run.
*
* @param line Text output line
* @param line - text output line
*/
private void parse(String line) {
if (line.startsWith(Prefixes.STATUS_CODE)) {
if (line.startsWith(STATUS_PREFIX_CODE)) {
// Previous status key-value has been collected. Store it.
submitCurrentKeyValue();
parseStatusCode(line);
} else if (line.startsWith(Prefixes.STATUS)) {
} else if (line.startsWith(STATUS_PREFIX)) {
// Previous status key-value has been collected. Store it.
submitCurrentKeyValue();
parseKey(line, Prefixes.STATUS.length());
} else if (line.startsWith(Prefixes.STATUS_FAILED)) {
parseKey(line, STATUS_PREFIX.length());
} else if (line.startsWith(STATUS_FAILED)) {
Log.e(LOG_TAG, "test run failed " + line);
mTestListener.testRunFailed(line);
} else if (line.startsWith(Prefixes.TIME_REPORT)) {
parseTime(line, Prefixes.TIME_REPORT.length());
} else if (line.startsWith(TIME_REPORT)) {
parseTime(line, TIME_REPORT.length());
} else {
if (mCurrentValue != null) {
// this is a value that has wrapped to next line.
@@ -177,53 +153,21 @@ public class InstrumentationResultParser extends MultiLineReceiver {
}
/**
* Stores the currently parsed key-value pair into mCurrentTestInfo.
* Stores the currently parsed key-value pair in the status map
*/
private void submitCurrentKeyValue() {
if (mCurrentKey != null && mCurrentValue != null) {
TestResult testInfo = getCurrentTestInfo();
String statusValue = mCurrentValue.toString();
if (mCurrentKey.equals(StatusKeys.CLASS)) {
testInfo.mTestClass = statusValue.trim();
}
else if (mCurrentKey.equals(StatusKeys.TEST)) {
testInfo.mTestName = statusValue.trim();
}
else if (mCurrentKey.equals(StatusKeys.NUMTESTS)) {
try {
testInfo.mNumTests = Integer.parseInt(statusValue);
}
catch (NumberFormatException e) {
Log.e(LOG_TAG, "Unexpected integer number of tests, received " + statusValue);
}
}
else if (mCurrentKey.equals(StatusKeys.STACK)) {
testInfo.mStackTrace = statusValue;
}
mStatusValues.put(mCurrentKey, mCurrentValue.toString());
mCurrentKey = null;
mCurrentValue = null;
}
}
private TestResult getCurrentTestInfo() {
if (mCurrentTestResult == null) {
mCurrentTestResult = new TestResult();
}
return mCurrentTestResult;
}
private void clearCurrentTestInfo() {
mCurrentTestResult = null;
}
/**
* Parses the key from the current line.
* Expects format of "key=value".
*
* @param line full line of text to parse
* @param keyStartPos the starting position of the key in the given line
* Parses the key from the current line
* Expects format of "key=value",
* @param line - full line of text to parse
* @param keyStartPos - the starting position of the key in the given line
*/
private void parseKey(String line, int keyStartPos) {
int endKeyPos = line.indexOf('=', keyStartPos);
@@ -235,7 +179,6 @@ public class InstrumentationResultParser extends MultiLineReceiver {
/**
* Parses the start of a key=value pair.
*
* @param line - full line of text to parse
* @param valueStartPos - the starting position of the value in the given line
*/
@@ -245,25 +188,20 @@ public class InstrumentationResultParser extends MultiLineReceiver {
}
/**
* Parses out a status code result.
* Parses out a status code result. For consistency, stores the result as a CODE entry in
* key-value status map
*/
private void parseStatusCode(String line) {
String value = line.substring(Prefixes.STATUS_CODE.length()).trim();
TestResult testInfo = getCurrentTestInfo();
try {
testInfo.mCode = Integer.parseInt(value);
}
catch (NumberFormatException e) {
Log.e(LOG_TAG, "Expected integer status code, received: " + value);
}
String value = line.substring(STATUS_PREFIX_CODE.length()).trim();
mStatusValues.put(CODE_KEY, value);
// this means we're done with current test result bundle
reportResult(testInfo);
clearCurrentTestInfo();
reportResult(mStatusValues);
mStatusValues.clear();
}
/**
* Returns true if test run canceled.
* Returns true if test run canceled
*
* @see IShellOutputReceiver#isCancelled()
*/
@@ -272,7 +210,7 @@ public class InstrumentationResultParser extends MultiLineReceiver {
}
/**
* Requests cancellation of test run.
* Requests cancellation of test result parsing
*/
public void cancel() {
mIsCancelled = true;
@@ -281,62 +219,82 @@ public class InstrumentationResultParser extends MultiLineReceiver {
/**
* Reports a test result to the test run listener. Must be called when a individual test
* result has been fully parsed.
*
* @param statusMap key-value status pairs of test result
* @param statusMap - key-value status pairs of test result
*/
private void reportResult(TestResult testInfo) {
if (!testInfo.isComplete()) {
Log.e(LOG_TAG, "invalid instrumentation status bundle " + testInfo.toString());
private void reportResult(Map<String, String> statusMap) {
String className = statusMap.get(CLASS_KEY);
String testName = statusMap.get(TEST_KEY);
String statusCodeString = statusMap.get(CODE_KEY);
if (className == null || testName == null || statusCodeString == null) {
Log.e(LOG_TAG, "invalid instrumentation status bundle " + statusMap.toString());
return;
}
reportTestRunStarted(testInfo);
TestIdentifier testId = new TestIdentifier(testInfo.mTestClass, testInfo.mTestName);
className = className.trim();
testName = testName.trim();
switch (testInfo.mCode) {
case StatusCodes.START:
mTestListener.testStarted(testId);
reportTestStarted(statusMap);
try {
int statusCode = Integer.parseInt(statusCodeString);
switch (statusCode) {
case START_STATUS_CODE:
mTestListener.testStarted(className, testName);
break;
case StatusCodes.FAILURE:
mTestListener.testFailed(ITestRunListener.TestFailure.FAILURE, testId,
getTrace(testInfo));
mTestListener.testEnded(testId);
case FAILURE_STATUS_CODE:
mTestListener.testFailed(ITestRunListener.STATUS_FAILURE, className, testName,
getTrace(statusMap));
mTestListener.testEnded(className, testName);
break;
case StatusCodes.ERROR:
mTestListener.testFailed(ITestRunListener.TestFailure.ERROR, testId,
getTrace(testInfo));
mTestListener.testEnded(testId);
case ERROR_STATUS_CODE:
mTestListener.testFailed(ITestRunListener.STATUS_ERROR, className, testName,
getTrace(statusMap));
mTestListener.testEnded(className, testName);
break;
case StatusCodes.OK:
mTestListener.testEnded(testId);
case OK_STATUS_CODE:
mTestListener.testEnded(className, testName);
break;
default:
Log.e(LOG_TAG, "Unknown status code received: " + testInfo.mCode);
mTestListener.testEnded(testId);
Log.e(LOG_TAG, "Expected status code, received: " + statusCodeString);
mTestListener.testEnded(className, testName);
break;
}
}
catch (NumberFormatException e) {
Log.e(LOG_TAG, "Expected integer status code, received: " + statusCodeString);
}
}
/**
* Reports the start of a test run, and the total test count, if it has not been previously
* reported.
*
* @param testInfo current test status values
* reported
* @param statusMap - key-value status pairs
*/
private void reportTestRunStarted(TestResult testInfo) {
private void reportTestStarted(Map<String, String> statusMap) {
// if start test run not reported yet
if (!mTestStartReported && testInfo.mNumTests != null) {
mTestListener.testRunStarted(testInfo.mNumTests);
if (!mTestStartReported) {
String numTestsString = statusMap.get(NUMTESTS_KEY);
if (numTestsString != null) {
try {
int numTests = Integer.parseInt(numTestsString);
mTestListener.testRunStarted(numTests);
mTestStartReported = true;
}
catch (NumberFormatException e) {
Log.e(LOG_TAG, "Unexpected numTests format " + numTestsString);
}
}
}
}
/**
* Returns the stack trace of the current failed test, from the provided testInfo.
* Returns the stack trace of the current failed test, from the provided key-value status map
*/
private String getTrace(TestResult testInfo) {
if (testInfo.mStackTrace != null) {
return testInfo.mStackTrace;
private String getTrace(Map<String, String> statusMap) {
String stackTrace = statusMap.get(STACK_KEY);
if (stackTrace != null) {
return stackTrace;
}
else {
Log.e(LOG_TAG, "Could not find stack trace for failed test ");
@@ -345,7 +303,7 @@ public class InstrumentationResultParser extends MultiLineReceiver {
}
/**
* Parses out and store the elapsed time.
* Parses out and store the elapsed time
*/
private void parseTime(String line, int startPos) {
String timeString = line.substring(startPos);

View File

@@ -23,7 +23,7 @@ import com.android.ddmlib.Log;
import java.io.IOException;
/**
* Runs a Android test command remotely and reports results.
* Runs a Android test command remotely and reports results
*/
public class RemoteAndroidTestRunner {
@@ -43,12 +43,11 @@ public class RemoteAndroidTestRunner {
"android.test.InstrumentationTestRunner";
/**
* Creates a remote Android test runner.
*
* @param packageName the Android application package that contains the tests to run
* @param runnerName the instrumentation test runner to execute. If null, will use default
* Creates a remote android test runner.
* @param packageName - the Android application package that contains the tests to run
* @param runnerName - the instrumentation test runner to execute. If null, will use default
* runner
* @param remoteDevice the Android device to execute tests on
* @param remoteDevice - the Android device to execute tests on
*/
public RemoteAndroidTestRunner(String packageName,
String runnerName,
@@ -63,10 +62,9 @@ public class RemoteAndroidTestRunner {
}
/**
* Alternate constructor. Uses default instrumentation runner.
*
* @param packageName the Android application package that contains the tests to run
* @param remoteDevice the Android device to execute tests on
* Alternate constructor. Uses default instrumentation runner
* @param packageName - the Android application package that contains the tests to run
* @param remoteDevice - the Android device to execute tests on
*/
public RemoteAndroidTestRunner(String packageName,
IDevice remoteDevice) {
@@ -74,14 +72,14 @@ public class RemoteAndroidTestRunner {
}
/**
* Returns the application package name.
* Returns the application package name
*/
public String getPackageName() {
return mPackageName;
}
/**
* Returns the runnerName.
* Returns the runnerName
*/
public String getRunnerName() {
if (mRunnerName == null) {
@@ -91,7 +89,7 @@ public class RemoteAndroidTestRunner {
}
/**
* Returns the complete instrumentation component path.
* Returns the complete instrumentation component path
*/
private String getRunnerPath() {
return getPackageName() + RUNNER_SEPARATOR + getRunnerName();
@@ -99,9 +97,8 @@ public class RemoteAndroidTestRunner {
/**
* Sets to run only tests in this class
* Must be called before 'run'.
*
* @param className fully qualified class name (eg x.y.z)
* Must be called before 'run'
* @param className - fully qualified class name (eg x.y.z)
*/
public void setClassName(String className) {
mClassArg = className;
@@ -109,12 +106,10 @@ public class RemoteAndroidTestRunner {
/**
* Sets to run only tests in the provided classes
* Must be called before 'run'.
* <p>
* Must be called before 'run'
* If providing more than one class, requires a InstrumentationTestRunner that supports
* the multiple class argument syntax.
*
* @param classNames array of fully qualified class names (eg x.y.z)
* the multiple class argument syntax
* @param classNames - array of fully qualified class name (eg x.y.z)
*/
public void setClassNames(String[] classNames) {
StringBuilder classArgBuilder = new StringBuilder();
@@ -130,10 +125,9 @@ public class RemoteAndroidTestRunner {
/**
* Sets to run only specified test method
* Must be called before 'run'.
*
* @param className fully qualified class name (eg x.y.z)
* @param testName method name
* Must be called before 'run'
* @param className - fully qualified class name (eg x.y.z)
* @param testName - method name
*/
public void setMethodName(String className, String testName) {
mClassArg = className + METHOD_SEPARATOR + testName;
@@ -141,9 +135,8 @@ public class RemoteAndroidTestRunner {
/**
* Sets extra arguments to include in instrumentation command.
* Must be called before 'run'.
*
* @param instrumentationArgs must not be null
* Must be called before 'run'
* @param instrumentationArgs - must not be null
*/
public void setExtraArgs(String instrumentationArgs) {
if (instrumentationArgs == null) {
@@ -153,23 +146,23 @@ public class RemoteAndroidTestRunner {
}
/**
* Returns the extra instrumentation arguments.
* Returns the extra instrumentation arguments
*/
public String getExtraArgs() {
return mExtraArgs;
}
/**
* Sets this test run to log only mode - skips test execution.
* Sets this test run to log only mode - skips test execution
*/
public void setLogOnly(boolean logOnly) {
mLogOnlyMode = logOnly;
}
/**
* Execute this test run.
* Execute this test run
*
* @param listener listens for test results
* @param listener - listener to report results to
*/
public void run(ITestRunListener listener) {
final String runCaseCommandStr = "am instrument -w -r "
@@ -186,7 +179,7 @@ public class RemoteAndroidTestRunner {
}
/**
* Requests cancellation of this test run.
* Requests cancellation of this test run
*/
public void cancel() {
if (mParser != null) {
@@ -195,7 +188,7 @@ public class RemoteAndroidTestRunner {
}
/**
* Returns the test class argument.
* Returns the test class argument
*/
private String getClassArg() {
return mClassArg;
@@ -203,7 +196,7 @@ public class RemoteAndroidTestRunner {
/**
* Returns the full instrumentation command which specifies the test classes to execute.
* Returns an empty string if no classes were specified.
* Returns an empty string if no classes were specified
*/
private String getClassCmd() {
String classArg = getClassArg();
@@ -215,7 +208,7 @@ public class RemoteAndroidTestRunner {
/**
* Returns the full command to enable log only mode - if specified. Otherwise returns an
* empty string.
* empty string
*/
private String getLogCmd() {
if (mLogOnlyMode) {

View File

@@ -1,76 +0,0 @@
/*
* 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.android.ddmlib.testrunner;
/**
* Identifies a parsed instrumentation test
*/
public class TestIdentifier {
private final String mClassName;
private final String mTestName;
/**
* Creates a test identifier
*
* @param className fully qualified class name of the test. Cannot be null.
* @param testName name of the test. Cannot be null.
*/
public TestIdentifier(String className, String testName) {
if (className == null || testName == null) {
throw new IllegalArgumentException("className and testName must " +
"be non-null");
}
mClassName = className;
mTestName = testName;
}
/**
* Returns the fully qualified class name of the test
*/
public String getClassName() {
return mClassName;
}
/**
* Returns the name of the test
*/
public String getTestName() {
return mTestName;
}
/**
* Tests equality by comparing class and method name
*/
@Override
public boolean equals(Object other) {
if (!(other instanceof TestIdentifier)) {
return false;
}
TestIdentifier otherTest = (TestIdentifier)other;
return getClassName().equals(otherTest.getClassName()) &&
getTestName().equals(otherTest.getTestName());
}
/**
* Generates hashCode based on class and method name.
*/
@Override
public int hashCode() {
return getClassName().hashCode() * 31 + getTestName().hashCode();
}
}

View File

@@ -20,7 +20,7 @@ import junit.framework.TestCase;
/**
* Tests InstrumentationResultParser.
* Tests InstrumentationResultParser
*/
public class InstrumentationResultParserTest extends TestCase {
@@ -51,7 +51,7 @@ public class InstrumentationResultParserTest extends TestCase {
/**
* Tests that the test run started and test start events is sent on first
* bundle received.
* bundle received
*/
public void testTestStarted() {
StringBuilder output = buildCommonResult();
@@ -63,7 +63,7 @@ public class InstrumentationResultParserTest extends TestCase {
}
/**
* Tests that a single successful test execution.
* Tests that a single successful test execution
*/
public void testTestSuccess() {
StringBuilder output = buildCommonResult();
@@ -74,11 +74,11 @@ public class InstrumentationResultParserTest extends TestCase {
injectTestString(output.toString());
assertCommonAttributes();
assertEquals(1, mTestResult.mNumTestsRun);
assertEquals(null, mTestResult.mTestStatus);
assertEquals(0, mTestResult.mTestStatus);
}
/**
* Test basic parsing of failed test case.
* Test basic parsing of failed test case
*/
public void testTestFailed() {
StringBuilder output = buildCommonResult();
@@ -91,12 +91,12 @@ public class InstrumentationResultParserTest extends TestCase {
assertCommonAttributes();
assertEquals(1, mTestResult.mNumTestsRun);
assertEquals(ITestRunListener.TestFailure.FAILURE, mTestResult.mTestStatus);
assertEquals(ITestRunListener.STATUS_FAILURE, mTestResult.mTestStatus);
assertEquals(STACK_TRACE, mTestResult.mTrace);
}
/**
* Test basic parsing and conversion of time from output.
* Test basic parsing and conversion of time from output
*/
public void testTimeParsing() {
final String timeString = "Time: 4.9";
@@ -105,7 +105,7 @@ public class InstrumentationResultParserTest extends TestCase {
}
/**
* builds a common test result using TEST_NAME and TEST_CLASS.
* builds a common test result using TEST_NAME and TEST_CLASS
*/
private StringBuilder buildCommonResult() {
StringBuilder output = new StringBuilder();
@@ -118,7 +118,7 @@ public class InstrumentationResultParserTest extends TestCase {
}
/**
* Adds common status results to the provided output.
* Adds common status results to the provided output
*/
private void addCommonStatus(StringBuilder output) {
addStatusKey(output, "stream", "\r\n" + CLASS_NAME);
@@ -130,7 +130,7 @@ public class InstrumentationResultParserTest extends TestCase {
}
/**
* Adds a stack trace status bundle to output.
* Adds a stack trace status bundle to output
*/
private void addStackTrace(StringBuilder output) {
addStatusKey(output, "stack", STACK_TRACE);
@@ -138,7 +138,7 @@ public class InstrumentationResultParserTest extends TestCase {
}
/**
* Helper method to add a status key-value bundle.
* Helper method to add a status key-value bundle
*/
private void addStatusKey(StringBuilder outputBuilder, String key,
String value) {
@@ -168,7 +168,7 @@ public class InstrumentationResultParserTest extends TestCase {
}
/**
* inject a test string into the result parser.
* inject a test string into the result parser
*
* @param result
*/
@@ -185,7 +185,7 @@ public class InstrumentationResultParserTest extends TestCase {
}
/**
* A specialized test listener that stores a single test events.
* A specialized test listener that stores a single test events
*/
private class VerifyingTestResult implements ITestRunListener {
@@ -194,28 +194,29 @@ public class InstrumentationResultParserTest extends TestCase {
int mNumTestsRun;
String mTestName;
long mTestTime;
TestFailure mTestStatus;
int mTestStatus;
String mTrace;
boolean mStopped;
VerifyingTestResult() {
mNumTestsRun = 0;
mTestStatus = null;
mTestStatus = 0;
mStopped = false;
}
public void testEnded(TestIdentifier test) {
public void testEnded(String className, String testName) {
mNumTestsRun++;
assertEquals("Unexpected class name", mSuiteName, test.getClassName());
assertEquals("Unexpected test ended", mTestName, test.getTestName());
assertEquals("Unexpected class name", mSuiteName, className);
assertEquals("Unexpected test ended", mTestName, testName);
}
public void testFailed(TestFailure status, TestIdentifier test, String trace) {
public void testFailed(int status, String className, String testName,
String trace) {
mTestStatus = status;
mTrace = trace;
assertEquals("Unexpected class name", mSuiteName, test.getClassName());
assertEquals("Unexpected test ended", mTestName, test.getTestName());
assertEquals("Unexpected class name", mSuiteName, className);
assertEquals("Unexpected test ended", mTestName, testName);
}
public void testRunEnded(long elapsedTime) {
@@ -232,9 +233,9 @@ public class InstrumentationResultParserTest extends TestCase {
mStopped = true;
}
public void testStarted(TestIdentifier test) {
mSuiteName = test.getClassName();
mTestName = test.getTestName();
public void testStarted(String className, String testName) {
mSuiteName = className;
mTestName = testName;
}
public void testRunFailed(String errorMessage) {

View File

@@ -31,7 +31,7 @@ import java.io.IOException;
import java.util.Map;
/**
* Tests RemoteAndroidTestRunner.
* Test RemoteAndroidTestRunner.
*/
public class RemoteAndroidTestRunnerTest extends TestCase {
@@ -51,7 +51,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
}
/**
* Test the basic case building of the instrumentation runner command with no arguments.
* Test the basic case building of the instrumentation runner command with no arguments
*/
public void testRun() {
mRunner.run(new EmptyListener());
@@ -60,7 +60,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
}
/**
* Test the building of the instrumentation runner command with log set.
* Test the building of the instrumentation runner command with log set
*/
public void testRunWithLog() {
mRunner.setLogOnly(true);
@@ -70,7 +70,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
}
/**
* Test the building of the instrumentation runner command with method set.
* Test the building of the instrumentation runner command with method set
*/
public void testRunWithMethod() {
final String className = "FooTest";
@@ -82,7 +82,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
}
/**
* Test the building of the instrumentation runner command with extra args set.
* Test the building of the instrumentation runner command with extra args set
*/
public void testRunWithExtraArgs() {
final String extraArgs = "blah";
@@ -94,7 +94,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
/**
* Assert two strings are equal ignoring whitespace.
* Assert two strings are equal ignoring whitespace
*/
private void assertStringsEquals(String str1, String str2) {
String strippedStr1 = str1.replaceAll(" ", "");
@@ -104,14 +104,14 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
/**
* A dummy device that does nothing except store the provided executed shell command for
* later retrieval.
* later retrieval
*/
private static class MockDevice implements IDevice {
private String mLastShellCommand;
/**
* Stores the provided command for later retrieval from getLastShellCommand.
* Stores the provided command for later retrieval from getLastShellCommand
*/
public void executeShellCommand(String command,
IShellOutputReceiver receiver) throws IOException {
@@ -119,7 +119,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
}
/**
* Get the last command provided to executeShellCommand.
* Get the last command provided to executeShellCommand
*/
public String getLastShellCommand() {
return mLastShellCommand;
@@ -201,26 +201,22 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
throw new UnsupportedOperationException();
}
public void runLogService(String logname, LogReceiver receiver) throws IOException {
throw new UnsupportedOperationException();
}
public String getAvdName() {
return "";
}
}
/**
* An empty implementation of ITestRunListener.
/** An empty implementation of TestRunListener
*/
private static class EmptyListener implements ITestRunListener {
public void testEnded(TestIdentifier test) {
public void testEnded(String className, String testName) {
// ignore
}
public void testFailed(TestFailure status, TestIdentifier test, String trace) {
public void testFailed(int status, String className, String testName,
String trace) {
// ignore
}
@@ -240,7 +236,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
// ignore
}
public void testStarted(TestIdentifier test) {
public void testStarted(String className, String testName) {
// ignore
}

View File

@@ -237,7 +237,7 @@ public final class NativeHeapPanel extends BaseHeapPanel {
*/
private HashMap<Long, NativeStackCallInfo> mSourceCache =
new HashMap<Long,NativeStackCallInfo>();
private long mTotalSize;
private int mTotalSize;
private Button mSaveButton;
private Button mSymbolsButton;

View File

@@ -20,9 +20,9 @@ rem Set up prog to be the path of this script, including following symlinks,
rem and set up progdir to be the fully-qualified pathname of its directory.
set prog=%~f0
rem Change current directory and drive to where the script is, to avoid
rem issues with directories containing whitespaces.
cd /d %~dp0
rem Change current directory to where ddms is, to avoid issues with directories
rem containing whitespaces.
cd %~dp0
set jarfile=draw9patch.jar
set frameworkdir=

View File

@@ -1,18 +1,14 @@
0.9.0 (work in progress)
- Support for the new Android SDK with support for multiple versions of the Android platform and for vendor supplied add-ons.
* New Project Wizard lets you choose which platform/add-on to target.
* Project properties (right click project in Package Explorer, then "Properties"), lets you edit project target.
* New Launch configuration option to choose debug deployment target.
- Ability to export multiple apk from one project, using resource filters. See the 'android' property for Android projects.
- Support for SDK with multiple versions of the Android platform and vendor supplied add-ons.
0.8.1:
- Alternate Layout wizard. In the layout editor, the "create" button is now enabled to easily create alternate versions of the current layout.
- Alternate Layout wizard. In the layout editor, the "create" button is now enabled, and allows to easily create alternate versions.
- Fixed issue with custom themes/styles in the layout editor.
- Export Wizard: To export an application for release, and sign it with a non debug key. Accessible from the export menu, from the Android Tools contextual menu, or from the overview page of the manifest editor.
- Export Wizard: To export an application for release, sign with a non debug key. Accessible from the export menu, from the Android Tools contextual menu, or from the overview page of the manifest editor.
- New XML File Wizard: To easily create new XML resources file in the /res directory.
- New checks on launch when attempting to debug on a device.
- Basic support for drag'n'drop in Graphical layout editor. You can add new items by drag'n'drop from the palette. There is no support for moving/resizing yet.
- Basic support for drag'n'drop in Graphical layout editor. You can add new items by drag'n'drop from the palette. There's is no support for moving/resizing yet.
- Undo/redo support in all XML form editors and Graphical layout editor.
0.8.0:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -17,14 +17,6 @@
<super type="org.eclipse.core.resources.textmarker"/>
<persistent value="true"/>
</extension>
<extension
id="com.android.ide.eclipse.common.aapt2Problem"
name="Android AAPT Problem"
point="org.eclipse.core.resources.markers">
<super type="org.eclipse.core.resources.problemmarker"/>
<super type="org.eclipse.core.resources.textmarker"/>
<persistent value="true"/>
</extension>
<extension
id="com.android.ide.eclipse.common.aidlProblem"
name="Android AIDL Problem"
@@ -472,31 +464,4 @@
</enabledWhen>
</page>
</extension>
<extension
point="org.eclipse.ui.actionSets">
<actionSet
description="Android Wizards"
id="adt.actionSet1"
label="Android Wizards"
visible="true">
<action
class="com.android.ide.eclipse.adt.wizards.actions.NewProjectAction"
icon="icons/new_adt_project.png"
id="com.android.ide.eclipse.adt.wizards.actions.NewProjectAction"
label="New Android Project"
style="push"
toolbarPath="android_project"
tooltip="Opens a wizard to help create a new Android project">
</action>
<action
class="com.android.ide.eclipse.adt.wizards.actions.NewXmlFileAction"
icon="icons/new_xml.png"
id="com.android.ide.eclipse.adt.wizards.actions.NewXmlFileAction"
label="New Android XML File"
style="push"
toolbarPath="android_project"
tooltip="Opens a wizard to help create a new Android XML file">
</action>
</actionSet>
</extension>
</plugin>

View File

@@ -28,7 +28,6 @@ import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerIni
import com.android.ide.eclipse.adt.sdk.AndroidTargetParser;
import com.android.ide.eclipse.adt.sdk.LoadStatus;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.EclipseUiHelper;
import com.android.ide.eclipse.common.SdkStatsHelper;
@@ -174,8 +173,7 @@ public class AdtPlugin extends AbstractUIPlugin {
private final ArrayList<IJavaProject> mPostLoadProjectsToCheck = new ArrayList<IJavaProject>();
private ResourceMonitor mResourceMonitor;
private ArrayList<ITargetChangeListener> mTargetChangeListeners =
new ArrayList<ITargetChangeListener>();
private ArrayList<Runnable> mResourceRefreshListener = new ArrayList<Runnable>();
/**
* Custom PrintStream for Dx output. This class overrides the method
@@ -863,6 +861,7 @@ public class AdtPlugin extends AbstractUIPlugin {
/**
* Returns the lock object for SDK loading. If you wish to do things while the SDK is loading,
* you must synchronize on this object.
* @return
*/
public final Object getSdkLockObject() {
return mPostLoadProjectsToResolve;
@@ -987,7 +986,7 @@ public class AdtPlugin extends AbstractUIPlugin {
Constants.BUNDLE_VERSION);
Version version = new Version(versionString);
SdkStatsHelper.pingUsageServer("adt", version); //$NON-NLS-1$
SdkStatsHelper.pingUsageServer("editors", version); //$NON-NLS-1$
return Status.OK_STATUS;
} catch (Throwable t) {
@@ -1020,12 +1019,8 @@ public class AdtPlugin extends AbstractUIPlugin {
progress.setTaskName(Messages.AdtPlugin_Parsing_Resources);
int n = sdk.getTargets().length;
if (n > 0) {
int w = 60 / n;
for (IAndroidTarget target : sdk.getTargets()) {
SubMonitor p2 = progress.newChild(w);
IStatus status = new AndroidTargetParser(target).run(p2);
IStatus status = new AndroidTargetParser(target).run(progress);
if (status.getCode() != IStatus.OK) {
synchronized (getSdkLockObject()) {
mSdkIsLoaded = LoadStatus.FAILED;
@@ -1034,13 +1029,14 @@ public class AdtPlugin extends AbstractUIPlugin {
return status;
}
}
}
// FIXME: move this per platform, or somewhere else.
progress = SubMonitor.convert(monitor,
Messages.AdtPlugin_Parsing_Resources, 20);
synchronized (getSdkLockObject()) {
mSdkIsLoaded = LoadStatus.LOADED;
progress.setTaskName("Check Projects");
// check the projects that need checking.
// The method modifies the list (it removes the project that
// do not need to be resolved again).
@@ -1056,33 +1052,25 @@ public class AdtPlugin extends AbstractUIPlugin {
AndroidClasspathContainerInitializer.updateProjects(array);
mPostLoadProjectsToResolve.clear();
}
progress.worked(10);
}
}
// Notify resource changed listeners
progress.setTaskName("Refresh UI");
progress.setWorkRemaining(mTargetChangeListeners.size());
progress.subTask("Refresh UI");
progress.setWorkRemaining(mResourceRefreshListener.size());
// Clone the list before iterating, to avoid Concurrent Modification
// exceptions
final List<ITargetChangeListener> listeners =
(List<ITargetChangeListener>)mTargetChangeListeners.clone();
final SubMonitor progress2 = progress;
AdtPlugin.getDisplay().syncExec(new Runnable() {
public void run() {
for (ITargetChangeListener listener : listeners) {
List<Runnable> listeners = (List<Runnable>)mResourceRefreshListener.clone();
for (Runnable listener : listeners) {
try {
listener.onTargetsLoaded();
AdtPlugin.getDisplay().syncExec(listener);
} catch (Exception e) {
AdtPlugin.log(e, "Failed to update a TargetChangeListener."); //$NON-NLS-1$
AdtPlugin.log(e, "ResourceRefreshListener Failed"); //$NON-NLS-1$
} finally {
progress2.worked(1);
progress.worked(1);
}
}
}
});
} finally {
if (monitor != null) {
monitor.done();
@@ -1328,42 +1316,12 @@ public class AdtPlugin extends AbstractUIPlugin {
}, IResourceDelta.ADDED | IResourceDelta.CHANGED);
}
/**
* Adds a new {@link ITargetChangeListener} to be notified when a new SDK is loaded, or when
* a project has its target changed.
*/
public void addTargetListener(ITargetChangeListener listener) {
mTargetChangeListeners.add(listener);
public void addResourceChangedListener(Runnable resourceRefreshListener) {
mResourceRefreshListener.add(resourceRefreshListener);
}
/**
* Removes an existing {@link ITargetChangeListener}.
* @see #addTargetListener(ITargetChangeListener)
*/
public void removeTargetListener(ITargetChangeListener listener) {
mTargetChangeListeners.remove(listener);
}
/**
* Updates all the {@link ITargetChangeListener} that a target has changed for a given project.
* <p/>Only editors related to that project should reload.
*/
@SuppressWarnings("unchecked")
public void updateTargetListener(final IProject project) {
final List<ITargetChangeListener> listeners =
(List<ITargetChangeListener>)mTargetChangeListeners.clone();
AdtPlugin.getDisplay().asyncExec(new Runnable() {
public void run() {
for (ITargetChangeListener listener : listeners) {
try {
listener.onProjectTargetChange(project);
} catch (Exception e) {
AdtPlugin.log(e, "Failed to update a TargetChangeListener."); //$NON-NLS-1$
}
}
}
});
public void removeResourceChangedListener(Runnable resourceRefreshListener) {
mResourceRefreshListener.remove(resourceRefreshListener);
}
public static synchronized OutputStream getErrorStream() {

View File

@@ -203,9 +203,6 @@ public class ApkBuilder extends BaseBuilder {
// get a project object
IProject project = getProject();
// Top level check to make sure the build can move forward.
abortOnBadSetup(project);
// get the list of referenced projects.
IProject[] referencedProjects = ProjectHelper.getReferencedProjects(project);
IJavaProject[] referencedJavaProjects = getJavaProjects(referencedProjects);
@@ -266,11 +263,68 @@ public class ApkBuilder extends BaseBuilder {
}
}
// do some extra check, in case the output files are not present. This
// will force to recreate them.
IResource tmp = null;
if (mPackageResources == false && outputFolder != null) {
tmp = outputFolder.findMember(AndroidConstants.FN_RESOURCES_AP_);
if (tmp == null || tmp.exists() == false) {
mPackageResources = true;
mBuildFinalPackage = true;
}
}
if (mConvertToDex == false && outputFolder != null) {
tmp = outputFolder.findMember(AndroidConstants.FN_CLASSES_DEX);
if (tmp == null || tmp.exists() == false) {
mConvertToDex = true;
mBuildFinalPackage = true;
}
}
// get the extra configs for the project. This will give us a list of custom apk
// to build based on a restricted set of resources.
Map<String, String> configs = Sdk.getCurrent().getProjectApkConfigs(project);
// also check the final file(s)!
String finalPackageName = getFileName(project, null /*config*/);
if (mBuildFinalPackage == false && outputFolder != null) {
tmp = outputFolder.findMember(finalPackageName);
if (tmp == null || (tmp instanceof IFile &&
tmp.exists() == false)) {
String msg = String.format(Messages.s_Missing_Repackaging, finalPackageName);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
mBuildFinalPackage = true;
}
if (configs != null) {
Set<Entry<String, String>> entrySet = configs.entrySet();
for (Entry<String, String> entry : entrySet) {
String filename = getFileName(project, entry.getKey());
tmp = outputFolder.findMember(filename);
if (tmp == null || (tmp instanceof IFile &&
tmp.exists() == false)) {
String msg = String.format(Messages.s_Missing_Repackaging,
finalPackageName);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
mBuildFinalPackage = true;
break;
}
}
}
}
// store the build status in the persistent storage
saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX , mConvertToDex);
saveProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, mPackageResources);
saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage);
// At this point, we can abort the build if we have to, as we have computed
// our resource delta and stored the result.
abortOnBadSetup(project);
if (dv != null && dv.mXmlError) {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.Xml_Error);
@@ -297,82 +351,6 @@ public class ApkBuilder extends BaseBuilder {
return referencedProjects;
}
// get the extra configs for the project.
// The map contains (name, filter) where 'name' is a name to be used in the apk filename,
// and filter is the resource filter to be used in the aapt -c parameters to restrict
// which resource configurations to package in the apk.
Map<String, String> configs = Sdk.getCurrent().getProjectApkConfigs(project);
// do some extra check, in case the output files are not present. This
// will force to recreate them.
IResource tmp = null;
if (mPackageResources == false) {
// check the full resource package
tmp = outputFolder.findMember(AndroidConstants.FN_RESOURCES_AP_);
if (tmp == null || tmp.exists() == false) {
mPackageResources = true;
mBuildFinalPackage = true;
} else {
// if the full package is present, we check the filtered resource packages as well
if (configs != null) {
Set<Entry<String, String>> entrySet = configs.entrySet();
for (Entry<String, String> entry : entrySet) {
String filename = String.format(AndroidConstants.FN_RESOURCES_S_AP_,
entry.getKey());
tmp = outputFolder.findMember(filename);
if (tmp == null || (tmp instanceof IFile &&
tmp.exists() == false)) {
String msg = String.format(Messages.s_Missing_Repackaging, filename);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
mPackageResources = true;
mBuildFinalPackage = true;
break;
}
}
}
}
}
// check classes.dex is present. If not we force to recreate it.
if (mConvertToDex == false) {
tmp = outputFolder.findMember(AndroidConstants.FN_CLASSES_DEX);
if (tmp == null || tmp.exists() == false) {
mConvertToDex = true;
mBuildFinalPackage = true;
}
}
// also check the final file(s)!
String finalPackageName = getFileName(project, null /*config*/);
if (mBuildFinalPackage == false) {
tmp = outputFolder.findMember(finalPackageName);
if (tmp == null || (tmp instanceof IFile &&
tmp.exists() == false)) {
String msg = String.format(Messages.s_Missing_Repackaging, finalPackageName);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
mBuildFinalPackage = true;
} else if (configs != null) {
// if the full apk is present, we check the filtered apk as well
Set<Entry<String, String>> entrySet = configs.entrySet();
for (Entry<String, String> entry : entrySet) {
String filename = getFileName(project, entry.getKey());
tmp = outputFolder.findMember(filename);
if (tmp == null || (tmp instanceof IFile &&
tmp.exists() == false)) {
String msg = String.format(Messages.s_Missing_Repackaging, filename);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
mBuildFinalPackage = true;
break;
}
}
}
}
// at this point we know if we need to recreate the temporary apk
// or the dex file, but we don't know if we simply need to recreate them
// because they are missing
@@ -418,9 +396,6 @@ public class ApkBuilder extends BaseBuilder {
// first we check if we need to package the resources.
if (mPackageResources) {
// remove some aapt_package only markers.
removeMarkersFromContainer(project, AndroidConstants.MARKER_AAPT_PACKAGE);
// need to figure out some path before we can execute aapt;
// resource to the AndroidManifest.xml file
@@ -577,8 +552,7 @@ public class ApkBuilder extends BaseBuilder {
* @param osAssetsPath The path to the assets folder. This can be null.
* @param osOutFilePath The path to the temporary resource file to create.
* @param configFilter The configuration filter for the resources to include
* (used with -c option, for example "port,en,fr" to include portrait, English and French
* resources.)
* (used with -c option)
* @return true if success, false otherwise.
*/
private boolean executeAapt(IProject project, String osManifestPath,

View File

@@ -149,15 +149,6 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
private final static Pattern sPattern8Line1 = Pattern.compile(
"^(invalid resource directory name): (.*)$"); //$NON-NLS-1$
/**
* 2 line aapt error<br>
* "ERROR: Invalid configuration: foo"<br>
* " ^^^"<br>
* There's no need to parse the 2nd line.
*/
private final static Pattern sPattern9Line1 = Pattern.compile(
"^Invalid configuration: (.+)$"); //$NON-NLS-1$
/** SAX Parser factory. */
private SAXParserFactory mParserFactory;
@@ -449,8 +440,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String location = m.group(1);
// check the values and attempt to mark the file.
if (checkAndMark(location, lineStr, msg, osRoot, project,
AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
if (checkAndMark(location, lineStr, msg, osRoot,
project, IMarker.SEVERITY_ERROR) == false) {
return true;
}
continue;
@@ -474,7 +465,7 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
// display the error
if (checkAndMark(location, null, msg, osRoot, project,
AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
IMarker.SEVERITY_ERROR) == false) {
return true;
}
@@ -497,8 +488,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String lineStr = m.group(2);
// check the values and attempt to mark the file.
if (checkAndMark(location, lineStr, msg, osRoot, project,
AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
if (checkAndMark(location, lineStr, msg, osRoot,
project, IMarker.SEVERITY_ERROR) == false) {
return true;
}
continue;
@@ -511,8 +502,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String msg = m.group(3);
// check the values and attempt to mark the file.
if (checkAndMark(location, lineStr, msg, osRoot, project,
AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
if (checkAndMark(location, lineStr, msg, osRoot,
project, IMarker.SEVERITY_ERROR) == false) {
return true;
}
@@ -535,8 +526,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String lineStr = m.group(2);
// check the values and attempt to mark the file.
if (checkAndMark(location, lineStr, msg, osRoot, project,
AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
if (checkAndMark(location, lineStr, msg, osRoot,
project, IMarker.SEVERITY_ERROR) == false) {
return true;
}
@@ -551,8 +542,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String msg = m.group(3);
// check the values and attempt to mark the file.
if (checkAndMark(location, lineStr, msg, osRoot, project,
AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_WARNING) == false) {
if (checkAndMark(location, lineStr, msg, osRoot,
project,IMarker.SEVERITY_WARNING) == false) {
return true;
}
@@ -567,8 +558,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String msg = m.group(3);
// check the values and attempt to mark the file.
if (checkAndMark(location, lineStr, msg, osRoot, project,
AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
if (checkAndMark(location, lineStr, msg, osRoot,
project, IMarker.SEVERITY_ERROR) == false) {
return true;
}
@@ -583,25 +574,7 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
// check the values and attempt to mark the file.
if (checkAndMark(location, null, msg, osRoot, project,
AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
return true;
}
// success, go to the next line
continue;
}
m = sPattern9Line1.matcher(p);
if (m.matches()) {
String badConfig = m.group(1);
String msg = String.format("APK Configuration filter '%1$s' is invalid", badConfig);
// skip the next line
i++;
// check the values and attempt to mark the file.
if (checkAndMark(null /*location*/, null, msg, osRoot, project,
AndroidConstants.MARKER_AAPT_PACKAGE, IMarker.SEVERITY_ERROR) == false) {
IMarker.SEVERITY_ERROR) == false) {
return true;
}
@@ -686,26 +659,24 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
/**
* Check if the parameters gotten from the error output are valid, and mark
* the file with an AAPT marker.
* @param location the full OS path of the error file. If null, the project is marked
* @param location
* @param lineStr
* @param message
* @param root The root directory of the project, in OS specific format.
* @param project
* @param markerId The marker id to put.
* @param severity The severity of the marker to put (IMarker.SEVERITY_*)
* @return true if the parameters were valid and the file was marked successfully.
* @return true if the parameters were valid and the file was marked
* sucessfully.
*
* @see IMarker
*/
private final boolean checkAndMark(String location, String lineStr,
String message, String root, IProject project, String markerId, int severity) {
String message, String root, IProject project, int severity) {
// check this is in fact a file
if (location != null) {
File f = new File(location);
if (f.exists() == false) {
return false;
}
}
// get the line number
int line = -1; // default value for error with no line.
@@ -721,18 +692,16 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
}
// add the marker
IResource f2 = project;
if (location != null) {
f2 = getResourceFromFullPath(location, root, project);
IResource f2 = getResourceFromFullPath(location, root, project);
if (f2 == null) {
return false;
}
}
// check if there's a similar marker already, since aapt is launched twice
boolean markerAlreadyExists = false;
try {
IMarker[] markers = f2.findMarkers(markerId, true, IResource.DEPTH_ZERO);
IMarker[] markers = f2.findMarkers(AndroidConstants.MARKER_AAPT, true,
IResource.DEPTH_ZERO);
for (IMarker marker : markers) {
int tmpLine = marker.getAttribute(IMarker.LINE_NUMBER, -1);
@@ -763,10 +732,10 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
if (markerAlreadyExists == false) {
if (line != -1) {
BaseProjectHelper.addMarker(f2, markerId, message, line,
BaseProjectHelper.addMarker(f2, AndroidConstants.MARKER_AAPT, message, line,
severity);
} else {
BaseProjectHelper.addMarker(f2, markerId, message, severity);
BaseProjectHelper.addMarker(f2, AndroidConstants.MARKER_AAPT, message, severity);
}
}
@@ -882,7 +851,7 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
* Aborts the build if the SDK/project setups are broken. This does not
* display any errors.
*
* @param project The {@link IJavaProject} being compiled.
* @param javaProject The {@link IJavaProject} being compiled.
* @throws CoreException
*/
protected final void abortOnBadSetup(IProject project) throws CoreException {

View File

@@ -57,11 +57,8 @@ public final class DexWrapper {
private Field mConsoleErr;
/**
* Loads the dex library from a file path.
*
* The loaded library can be used via
* {@link DexWrapper#run(String, String[], boolean, PrintStream, PrintStream)}.
*
* Loads the dex library from a file path. The loaded library can be used with the
* {@link DexWrapper} object returned by {@link #getWrapper()}
* @param osFilepath the location of the dex.jar file.
* @return an IStatus indicating the result of the load.
*/

View File

@@ -234,10 +234,6 @@ public class PreCompilerBuilder extends BaseBuilder {
// get the project objects
IProject project = getProject();
// Top level check to make sure the build can move forward.
abortOnBadSetup(project);
IJavaProject javaProject = JavaCore.create(project);
IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project);
@@ -288,6 +284,10 @@ public class PreCompilerBuilder extends BaseBuilder {
saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES , mCompileResources);
// TODO also needs to store the list of aidl to compile/remove
// At this point we have stored what needs to be build, so we can
// do some high level test and abort if needed.
abortOnBadSetup(project);
// if there was some XML errors, we just return w/o doing
// anything since we've put some markers in the files anyway.
if (dv != null && dv.mXmlError) {
@@ -381,7 +381,7 @@ public class PreCompilerBuilder extends BaseBuilder {
// mark the manifest file
String message = String.format(Messages.Package_s_Doesnt_Exist_Error,
mManifestPackage);
BaseProjectHelper.addMarker(manifest, AndroidConstants.MARKER_AAPT_COMPILE, message,
BaseProjectHelper.addMarker(manifest, AndroidConstants.MARKER_AAPT, message,
IMarker.SEVERITY_ERROR);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, message);
@@ -409,8 +409,8 @@ public class PreCompilerBuilder extends BaseBuilder {
String osManifestPath = manifestLocation.toOSString();
// remove the aapt markers
removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT_COMPILE);
removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT_COMPILE);
removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT);
removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.Preparing_Generated_Files);

View File

@@ -17,19 +17,11 @@
package com.android.ide.eclipse.adt.preferences;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
import com.android.sdklib.IAndroidTarget;
import com.android.sdkuilib.SdkTargetSelector;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.preference.DirectoryFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
@@ -88,9 +80,6 @@ public class AndroidPreferencePage extends FieldEditorPreferencePage implements
*/
private static class SdkDirectoryFieldEditor extends DirectoryFieldEditor {
private SdkTargetSelector mTargetSelector;
private TargetChangedListener mTargetChangeListener;
public SdkDirectoryFieldEditor(String name, String labelText, Composite parent) {
super(name, labelText, parent);
setEmptyStringAllowed(false);
@@ -142,68 +131,5 @@ public class AndroidPreferencePage extends FieldEditorPreferencePage implements
setValidateStrategy(VALIDATE_ON_KEY_STROKE);
return super.getTextControl(parent);
}
/* (non-Javadoc)
* Method declared on StringFieldEditor (and FieldEditor).
*/
@Override
protected void doFillIntoGrid(Composite parent, int numColumns) {
super.doFillIntoGrid(parent, numColumns);
GridData gd;
Label l = new Label(parent, SWT.NONE);
l.setText("Note: The list of SDK Targets below is only reloaded once you hit 'Apply' or 'OK'.");
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = numColumns;
l.setLayoutData(gd);
try {
// We may not have an sdk if the sdk path pref is empty or not valid.
Sdk sdk = Sdk.getCurrent();
IAndroidTarget[] targets = sdk != null ? sdk.getTargets() : null;
mTargetSelector = new SdkTargetSelector(parent,
targets,
false, /*allowSelection*/
false /*multipleSelection*/);
gd = (GridData) mTargetSelector.getLayoutData();
gd.horizontalSpan = numColumns;
if (mTargetChangeListener == null) {
mTargetChangeListener = new TargetChangedListener();
AdtPlugin.getDefault().addTargetListener(mTargetChangeListener);
}
} catch (Exception e) {
// We need to catch *any* exception that arises here, otherwise it disables
// the whole pref panel. We can live without the Sdk target selector but
// not being able to actually set an sdk path.
AdtPlugin.log(e, "SdkTargetSelector failed");
}
}
@Override
public void dispose() {
super.dispose();
if (mTargetChangeListener != null) {
AdtPlugin.getDefault().removeTargetListener(mTargetChangeListener);
mTargetChangeListener = null;
}
}
private class TargetChangedListener implements ITargetChangeListener {
public void onProjectTargetChange(IProject changedProject) {
// do nothing.
}
public void onTargetsLoaded() {
if (mTargetSelector != null) {
// We may not have an sdk if the sdk path pref is empty or not valid.
Sdk sdk = Sdk.getCurrent();
IAndroidTarget[] targets = sdk != null ? sdk.getTargets() : null;
mTargetSelector.setTargets(targets);
}
}
}
}
}

View File

@@ -266,6 +266,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
// We schedule a new job to put the marker after.
final String fmessage = markerMessage;
Job markerJob = new Job("Android SDK: Resolving error markers") {
@SuppressWarnings("unchecked")
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
@@ -295,6 +296,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
// In some cases, the workspace may be locked for modification when we pass
// here, so we schedule a new job to put the marker after.
Job markerJob = new Job("Android SDK: Resolving error markers") {
@SuppressWarnings("unchecked")
@Override
protected IStatus run(IProgressMonitor monitor) {
try {

View File

@@ -18,7 +18,6 @@ package com.android.ide.eclipse.adt.project.properties;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.sdklib.IAndroidTarget;
import com.android.sdkuilib.ApkConfigWidget;
import com.android.sdkuilib.SdkTargetSelector;
import org.eclipse.core.resources.IProject;
@@ -33,8 +32,6 @@ import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IWorkbenchPropertyPage;
import org.eclipse.ui.dialogs.PropertyPage;
import java.util.Map;
/**
* Property page for "Android" project.
* This is accessible from the Package Explorer when right clicking a project and choosing
@@ -45,7 +42,6 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope
private IProject mProject;
private SdkTargetSelector mSelector;
private ApkConfigWidget mApkConfigWidget;
public AndroidPropertyPage() {
// pass
@@ -56,13 +52,6 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope
// get the element (this is not yet valid in the constructor).
mProject = (IProject)getElement();
// get the targets from the sdk
IAndroidTarget[] targets = null;
if (Sdk.getCurrent() != null) {
targets = Sdk.getCurrent().getTargets();
}
// build the UI.
Composite top = new Composite(parent, SWT.NONE);
top.setLayoutData(new GridData(GridData.FILL_BOTH));
top.setLayout(new GridLayout(1, false));
@@ -70,28 +59,20 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope
Label l = new Label(top, SWT.NONE);
l.setText("Project Target");
// get the targets from the sdk
IAndroidTarget[] targets = null;
if (Sdk.getCurrent() != null) {
targets = Sdk.getCurrent().getTargets();
}
// build the UI.
mSelector = new SdkTargetSelector(top, targets, false /*allowMultipleSelection*/);
l = new Label(top, SWT.SEPARATOR | SWT.HORIZONTAL);
l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
l = new Label(top, SWT.NONE);
l.setText("Project APK Configurations");
mApkConfigWidget = new ApkConfigWidget(top);
// fill the ui
Sdk currentSdk = Sdk.getCurrent();
if (currentSdk != null && mProject.isOpen()) {
// get the target
IAndroidTarget target = currentSdk.getTarget(mProject);
if (Sdk.getCurrent() != null) {
IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
if (target != null) {
mSelector.setSelection(target);
}
// get the apk configurations
Map<String, String> configs = currentSdk.getProjectApkConfigs(mProject);
mApkConfigWidget.fillTable(configs);
}
mSelector.setSelectionListener(new SelectionAdapter() {
@@ -103,19 +84,13 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope
}
});
if (mProject.isOpen() == false) {
// disable the ui.
}
return top;
}
@Override
public boolean performOk() {
Sdk currentSdk = Sdk.getCurrent();
if (currentSdk != null) {
currentSdk.setProject(mProject, mSelector.getFirstSelected(),
mApkConfigWidget.getApkConfigs());
if (Sdk.getCurrent() != null) {
Sdk.getCurrent().setProject(mProject, mSelector.getFirstSelected());
}
return true;

View File

@@ -27,7 +27,6 @@ import com.android.ide.eclipse.editors.resources.manager.ProjectResources;
import com.android.ide.eclipse.editors.xml.descriptors.XmlDescriptors;
import com.android.layoutlib.api.ILayoutBridge;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
import java.util.Hashtable;
import java.util.Map;
@@ -44,7 +43,6 @@ public class AndroidTargetData {
public final static int DESCRIPTOR_RESOURCES = 5;
public final static int DESCRIPTOR_SEARCHABLE = 6;
public final static int DESCRIPTOR_PREFERENCES = 7;
public final static int DESCRIPTOR_GADGET_PROVIDER = 8;
public final static class LayoutBridge {
/** Link to the layout bridge */
@@ -53,8 +51,6 @@ public class AndroidTargetData {
public LoadStatus status = LoadStatus.LOADING;
public ClassLoader classLoader;
public int apiLevel;
}
private final IAndroidTarget mTarget;
@@ -97,7 +93,6 @@ public class AndroidTargetData {
/**
* Creates an AndroidTargetData object.
* @param optionalLibraries
*/
void setExtraData(IResourceRepository systemResourceRepository,
AndroidManifestDescriptors manifestDescriptors,
@@ -110,7 +105,6 @@ public class AndroidTargetData {
String[] broadcastIntentActionValues,
String[] serviceIntentActionValues,
String[] intentCategoryValues,
IOptionalLibrary[] optionalLibraries,
ProjectResources resources,
LayoutBridge layoutBridge) {
@@ -126,7 +120,6 @@ public class AndroidTargetData {
setPermissions(permissionValues);
setIntentFilterActionsAndCategories(activityIntentActionValues, broadcastIntentActionValues,
serviceIntentActionValues, intentCategoryValues);
setOptionalLibraries(optionalLibraries);
}
public DexWrapper getDexWrapper() {
@@ -158,8 +151,6 @@ public class AndroidTargetData {
return ResourcesDescriptors.getInstance();
case DESCRIPTOR_PREFERENCES:
return mXmlDescriptors.getPreferencesProvider();
case DESCRIPTOR_GADGET_PROVIDER:
return mXmlDescriptors.getGadgetProvider();
case DESCRIPTOR_SEARCHABLE:
return mXmlDescriptors.getSearchableProvider();
default :
@@ -293,20 +284,6 @@ public class AndroidTargetData {
setValues("(category,android:name)", intentCategoryValues); //$NON-NLS-1$
}
private void setOptionalLibraries(IOptionalLibrary[] optionalLibraries) {
String[] values;
if (optionalLibraries == null) {
values = new String[0];
} else {
values = new String[optionalLibraries.length];
for (int i = 0; i < optionalLibraries.length; i++) {
values[i] = optionalLibraries[i].getName();
}
}
setValues("(uses-library,android:name)", values);
}
/**
* Sets a (name, values) pair in the hash map.
* <p/>

View File

@@ -92,7 +92,7 @@ public final class AndroidTargetParser {
try {
SubMonitor progress = SubMonitor.convert(monitor,
String.format("Parsing SDK %1$s", mAndroidTarget.getName()),
14);
200);
AndroidTargetData targetData = new AndroidTargetData(mAndroidTarget);
@@ -107,14 +107,15 @@ public final class AndroidTargetParser {
// we have loaded dx.
targetData.setDexWrapper(dexWrapper);
progress.worked(1);
// parse the rest of the data.
progress.setWorkRemaining(120);
AndroidJarLoader classLoader =
new AndroidJarLoader(mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR));
preload(classLoader, progress.newChild(40, SubMonitor.SUPPRESS_NONE));
progress.setWorkRemaining(80);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -123,7 +124,7 @@ public final class AndroidTargetParser {
// get the resource Ids.
progress.subTask("Resource IDs");
IResourceRepository frameworkRepository = collectResourceIds(classLoader);
progress.worked(1);
progress.worked(5);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -132,7 +133,7 @@ public final class AndroidTargetParser {
// get the permissions
progress.subTask("Permissions");
String[] permissionValues = collectPermissions(classLoader);
progress.worked(1);
progress.worked(5);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -146,7 +147,7 @@ public final class AndroidTargetParser {
ArrayList<String> categories = new ArrayList<String>();
collectIntentFilterActionsAndCategories(activity_actions, broadcast_actions,
service_actions, categories);
progress.worked(1);
progress.worked(5);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -157,14 +158,12 @@ public final class AndroidTargetParser {
AttrsXmlParser attrsXmlParser = new AttrsXmlParser(
mAndroidTarget.getPath(IAndroidTarget.ATTRIBUTES));
attrsXmlParser.preload();
progress.worked(1);
progress.subTask("Manifest definitions");
AttrsXmlParser attrsManifestXmlParser = new AttrsXmlParser(
mAndroidTarget.getPath(IAndroidTarget.MANIFEST_ATTRIBUTES),
attrsXmlParser);
attrsManifestXmlParser.preload();
progress.worked(1);
Collection<ViewClassInfo> mainList = new ArrayList<ViewClassInfo>();
Collection<ViewClassInfo> groupList = new ArrayList<ViewClassInfo>();
@@ -172,7 +171,7 @@ public final class AndroidTargetParser {
// collect the layout/widgets classes
progress.subTask("Widgets and layouts");
collectLayoutClasses(classLoader, attrsXmlParser, mainList, groupList,
progress.newChild(1));
progress.newChild(40));
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -186,7 +185,7 @@ public final class AndroidTargetParser {
mainList.clear();
groupList.clear();
collectPreferenceClasses(classLoader, attrsXmlParser, mainList, groupList,
progress.newChild(1));
progress.newChild(5));
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -203,11 +202,6 @@ public final class AndroidTargetParser {
attrsManifestXmlParser);
Map<String, Map<String, Integer>> enumValueMap = attrsXmlParser.getEnumFlagValues();
Map<String, DeclareStyleableInfo> xmlGadgetMap = null;
if (mAndroidTarget.getApiVersionNumber() >= 3) {
xmlGadgetMap = collectGadgetDefinitions(attrsXmlParser);
}
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
}
@@ -216,7 +210,7 @@ public final class AndroidTargetParser {
// the PlatformData object.
AndroidManifestDescriptors manifestDescriptors = new AndroidManifestDescriptors();
manifestDescriptors.updateDescriptors(manifestMap);
progress.worked(1);
progress.worked(10);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -224,7 +218,7 @@ public final class AndroidTargetParser {
LayoutDescriptors layoutDescriptors = new LayoutDescriptors();
layoutDescriptors.updateDescriptors(layoutViewsInfo, layoutGroupsInfo);
progress.worked(1);
progress.worked(10);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -232,28 +226,25 @@ public final class AndroidTargetParser {
MenuDescriptors menuDescriptors = new MenuDescriptors();
menuDescriptors.updateDescriptors(xmlMenuMap);
progress.worked(1);
progress.worked(10);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
}
XmlDescriptors xmlDescriptors = new XmlDescriptors();
xmlDescriptors.updateDescriptors(
xmlSearchableMap,
xmlGadgetMap,
preferencesInfo,
xmlDescriptors.updateDescriptors(xmlSearchableMap, preferencesInfo,
preferenceGroupsInfo);
progress.worked(1);
progress.worked(10);
// load the framework resources.
ProjectResources resources = ResourceManager.getInstance().loadFrameworkResources(
mAndroidTarget);
progress.worked(1);
progress.worked(10);
// now load the layout lib bridge
LayoutBridge layoutBridge = loadLayoutBridge();
progress.worked(1);
progress.worked(10);
// and finally create the PlatformData with all that we loaded.
targetData.setExtraData(frameworkRepository,
@@ -267,7 +258,6 @@ public final class AndroidTargetParser {
broadcast_actions.toArray(new String[broadcast_actions.size()]),
service_actions.toArray(new String[service_actions.size()]),
categories.toArray(new String[categories.size()]),
mAndroidTarget.getOptionalLibraries(),
resources,
layoutBridge);
@@ -278,6 +268,10 @@ public final class AndroidTargetParser {
AdtPlugin.logAndPrintError(e, TAG, "SDK parser failed"); //$NON-NLS-1$
AdtPlugin.printToConsole("SDK parser failed", e.getMessage());
return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "SDK parser failed", e);
} finally {
if (monitor != null) {
monitor.done();
}
}
}
@@ -610,31 +604,6 @@ public final class AndroidTargetParser {
return Collections.unmodifiableMap(map2);
}
/**
* Collects all gadgetProviderInfo definition information from the attrs.xml and returns it.
*
* @param attrsXmlParser The parser of the attrs.xml file
*/
private Map<String, DeclareStyleableInfo> collectGadgetDefinitions(
AttrsXmlParser attrsXmlParser) {
Map<String, DeclareStyleableInfo> map = attrsXmlParser.getDeclareStyleableList();
Map<String, DeclareStyleableInfo> map2 = new HashMap<String, DeclareStyleableInfo>();
for (String key : new String[] { "GadgetProviderInfo" }) { //$NON-NLS-1$
if (map.containsKey(key)) {
map2.put(key, map.get(key));
} else {
AdtPlugin.log(IStatus.WARNING,
"Gadget declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$
key, attrsXmlParser.getOsAttrsXmlPath());
AdtPlugin.printErrorToConsole("Android Framework Parser",
String.format("Gadget declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$
key, attrsXmlParser.getOsAttrsXmlPath()));
}
}
return Collections.unmodifiableMap(map2);
}
/**
* Collects all manifest definition information from the attrs_manifest.xml and returns it.
*/
@@ -681,15 +650,6 @@ public final class AndroidTargetParser {
layoutBridge.status = LoadStatus.FAILED;
AdtPlugin.log(IStatus.ERROR, "Failed to load " + AndroidConstants.CLASS_BRIDGE); //$NON-NLS-1$
} else {
// get the api level
try {
layoutBridge.apiLevel = layoutBridge.bridge.getApiLevel();
} catch (AbstractMethodError e) {
// the first version of the api did not have this method
layoutBridge.apiLevel = 1;
}
// and mark the lib as loaded.
layoutBridge.status = LoadStatus.LOADED;
}
}

View File

@@ -18,7 +18,6 @@ package com.android.ide.eclipse.adt.sdk;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer;
import com.android.ide.eclipse.adt.sdk.AndroidTargetData.LayoutBridge;
import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor;
import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener;
import com.android.prefs.AndroidLocation.AndroidLocationException;
@@ -34,7 +33,6 @@ import com.android.sdklib.project.ProjectProperties.PropertyType;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
@@ -70,22 +68,6 @@ public class Sdk implements IProjectListener {
new HashMap<IProject, Map<String, String>>();
private final String mDocBaseUrl;
/**
* Classes implementing this interface will receive notification when targets are changed.
*/
public interface ITargetChangeListener {
/**
* Sent when project has its target changed.
*/
void onProjectTargetChange(IProject changedProject);
/**
* Called when the targets are loaded (either the SDK finished loading when Eclipse starts,
* or the SDK is changed).
*/
void onTargetsLoaded();
}
/**
* Loads an SDK and returns an {@link Sdk} object if success.
* @param sdkLocation the OS path to the SDK.
@@ -181,87 +163,24 @@ public class Sdk implements IProjectListener {
}
/**
* Sets a new target and a new list of Apk configuration for a given project.
*
* @param project the project to receive the new apk configurations
* @param target The new target to set, or <code>null</code> to not change the current target.
* @param apkConfigMap a map of apk configurations. The map contains (name, filter) where name
* is the name of the configuration (a-zA-Z0-9 only), and filter is the comma separated list of
* resource configuration to include in the apk (see aapt -c). Can be <code>null</code> if the
* apk configurations should not be updated.
* Associates an {@link IProject} and an {@link IAndroidTarget}.
*/
public void setProject(IProject project, IAndroidTarget target,
Map<String, String> apkConfigMap) {
public void setProject(IProject project, IAndroidTarget target) {
synchronized (mProjectTargetMap) {
boolean resolveProject = false;
boolean compileProject = false;
boolean cleanProject = false;
ProjectProperties properties = ProjectProperties.load(
project.getLocation().toOSString(), PropertyType.DEFAULT);
if (properties == null) {
// doesn't exist yet? we create it.
properties = ProjectProperties.create(project.getLocation().toOSString(),
PropertyType.DEFAULT);
}
if (target != null) {
// look for the current target of the project
IAndroidTarget previousTarget = mProjectTargetMap.get(project);
if (target != previousTarget) {
// save the target hash string in the project persistent property
properties.setAndroidTarget(target);
setProjectTargetHashString(project, target.hashString());
// put it in a local map for easy access.
mProjectTargetMap.put(project, target);
resolveProject = true;
}
}
if (apkConfigMap != null) {
// save the apk configs in the project persistent property
cleanProject = ApkConfigurationHelper.setConfigs(properties, apkConfigMap);
// put it in a local map for easy access.
mProjectApkConfigMap.put(project, apkConfigMap);
compileProject = true;
}
// we are done with the modification. Save the property file.
try {
properties.save();
} catch (IOException e) {
AdtPlugin.log(e, "Failed to save default.properties for project '%s'",
project.getName());
}
if (resolveProject) {
// force a resolve of the project by updating the classpath container.
// recompile the project if needed.
IJavaProject javaProject = JavaCore.create(project);
AndroidClasspathContainerInitializer.updateProjects(
new IJavaProject[] { javaProject });
} else if (compileProject) {
// If there was removed configs, we clean instead of build
// (to remove the obsolete ap_ and apk file from removed configs).
try {
project.build(cleanProject ?
IncrementalProjectBuilder.CLEAN_BUILD :
IncrementalProjectBuilder.FULL_BUILD,
null);
} catch (CoreException e) {
// failed to build? force resolve instead.
IJavaProject javaProject = JavaCore.create(project);
AndroidClasspathContainerInitializer.updateProjects(
new IJavaProject[] { javaProject });
}
}
// finally, update the opened editors.
if (resolveProject) {
AdtPlugin.getDefault().updateTargetListener(project);
}
}
}
@@ -299,12 +218,7 @@ public class Sdk implements IProjectListener {
*/
private static String loadProjectProperties(IProject project, Sdk sdkStorage) {
// load the default.properties from the project folder.
IPath location = project.getLocation();
if (location == null) { // can return null when the project is being deleted.
// do nothing and return null;
return null;
}
ProjectProperties properties = ProjectProperties.load(location.toOSString(),
ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(),
PropertyType.DEFAULT);
if (properties == null) {
AdtPlugin.log(IStatus.ERROR, "Failed to load properties file for project '%s'",
@@ -315,7 +229,7 @@ public class Sdk implements IProjectListener {
if (sdkStorage != null) {
Map<String, String> configMap = ApkConfigurationHelper.getConfigs(properties);
if (configMap != null) {
if (configMap.size() > 0) {
sdkStorage.mProjectApkConfigMap.put(project, configMap);
}
}
@@ -382,6 +296,40 @@ public class Sdk implements IProjectListener {
return mProjectApkConfigMap.get(project);
}
public void setProjectApkConfigs(IProject project, Map<String, String> configMap)
throws CoreException {
// first set the new map
mProjectApkConfigMap.put(project, configMap);
// Now we write this in default.properties.
// Because we don't want to erase other properties from default.properties, we first load
// them
ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(),
PropertyType.DEFAULT);
if (properties == null) {
// doesn't exist yet? we create it.
properties = ProjectProperties.create(project.getLocation().toOSString(),
PropertyType.DEFAULT);
}
// sets the configs in the property file.
boolean hasRemovedConfig = ApkConfigurationHelper.setConfigs(properties, configMap);
// and rewrite the file.
try {
properties.save();
} catch (IOException e) {
AdtPlugin.log(e, "Failed to save default.properties for project '%s'",
project.getName());
}
// we're done, force a rebuild. If there was removed config, we clean instead of build
// (to remove the obsolete ap_ and apk file from removed configs).
project.build(hasRemovedConfig ?
IncrementalProjectBuilder.CLEAN_BUILD : IncrementalProjectBuilder.FULL_BUILD,
null);
}
/**
* Returns the {@link AvdManager}. If the AvdManager failed to parse the AVD folder, this could
* be <code>null</code>.
@@ -454,25 +402,9 @@ public class Sdk implements IProjectListener {
}
public void projectClosed(IProject project) {
// get the target project
synchronized (mProjectTargetMap) {
IAndroidTarget target = mProjectTargetMap.get(project);
if (target != null) {
// get the bridge for the target, and clear the cache for this project.
AndroidTargetData data = mTargetDataMap.get(target);
if (data != null) {
LayoutBridge bridge = data.getLayoutBridge();
if (bridge != null && bridge.status == LoadStatus.LOADED) {
bridge.bridge.clearCaches(project);
}
}
}
// now remove the project for the maps.
mProjectTargetMap.remove(project);
mProjectApkConfigMap.remove(project);
}
}
public void projectDeleted(IProject project) {
projectClosed(project);

View File

@@ -1,34 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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.ide.eclipse.adt.wizards.actions;
import com.android.ide.eclipse.adt.wizards.newproject.NewProjectWizard;
import org.eclipse.jface.action.IAction;
import org.eclipse.ui.IWorkbenchWizard;
/**
* Delegate for the toolbar action "Android Project".
* It displays the Android New Project wizard.
*/
public class NewProjectAction extends OpenWizardAction {
@Override
protected IWorkbenchWizard instanciateWizard(IAction action) {
return new NewProjectWizard();
}
}

View File

@@ -1,34 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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.ide.eclipse.adt.wizards.actions;
import com.android.ide.eclipse.editors.wizards.NewXmlFileWizard;
import org.eclipse.jface.action.IAction;
import org.eclipse.ui.IWorkbenchWizard;
/**
* Delegate for the toolbar action "Android Project".
* It displays the Android New XML file wizard.
*/
public class NewXmlFileAction extends OpenWizardAction {
@Override
protected IWorkbenchWizard instanciateWizard(IAction action) {
return new NewXmlFileWizard();
}
}

View File

@@ -1,139 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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.ide.eclipse.adt.wizards.actions;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.IWorkbenchWizard;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
import org.eclipse.ui.internal.LegacyResourceSupport;
import org.eclipse.ui.internal.actions.NewWizardShortcutAction;
import org.eclipse.ui.internal.util.Util;
/**
* An abstract action that displays one of our wizards.
* Derived classes must provide the actual wizard to display.
*/
/*package*/ abstract class OpenWizardAction implements IWorkbenchWindowActionDelegate {
/**
* The wizard dialog width, extracted from {@link NewWizardShortcutAction}
*/
private static final int SIZING_WIZARD_WIDTH = 500;
/**
* The wizard dialog height, extracted from {@link NewWizardShortcutAction}
*/
private static final int SIZING_WIZARD_HEIGHT = 500;
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose()
*/
public void dispose() {
// pass
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchWindowActionDelegate#init(org.eclipse.ui.IWorkbenchWindow)
*/
public void init(IWorkbenchWindow window) {
// pass
}
/**
* Opens and display the Android New Project Wizard.
* <p/>
* Most of this implementation is extracted from {@link NewWizardShortcutAction#run()}.
*
* @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
*/
public void run(IAction action) {
// get the workbench and the current window
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
// This code from NewWizardShortcutAction#run() gets the current window selection
// and converts it to a workbench structured selection for the wizard, if possible.
ISelection selection = window.getSelectionService().getSelection();
IStructuredSelection selectionToPass = StructuredSelection.EMPTY;
if (selection instanceof IStructuredSelection) {
selectionToPass = (IStructuredSelection) selection;
} else {
// Build the selection from the IFile of the editor
IWorkbenchPart part = window.getPartService().getActivePart();
if (part instanceof IEditorPart) {
IEditorInput input = ((IEditorPart) part).getEditorInput();
Class<?> fileClass = LegacyResourceSupport.getFileClass();
if (input != null && fileClass != null) {
Object file = Util.getAdapter(input, fileClass);
if (file != null) {
selectionToPass = new StructuredSelection(file);
}
}
}
}
// Create the wizard and initialize it with the selection
IWorkbenchWizard wizard = instanciateWizard(action);
wizard.init(workbench, selectionToPass);
// It's not visible yet until a dialog is created and opened
Shell parent = window.getShell();
WizardDialog dialog = new WizardDialog(parent, wizard);
dialog.create();
// This code comes straight from NewWizardShortcutAction#run()
Point defaultSize = dialog.getShell().getSize();
dialog.getShell().setSize(
Math.max(SIZING_WIZARD_WIDTH, defaultSize.x),
Math.max(SIZING_WIZARD_HEIGHT, defaultSize.y));
window.getWorkbench().getHelpSystem().setHelp(dialog.getShell(),
IWorkbenchHelpContextIds.NEW_WIZARD_SHORTCUT);
dialog.open();
}
/**
* Called by {@link #run(IAction)} to instantiate the actual wizard.
*
* @param action The action parameter from {@link #run(IAction)}.
* @return A new wizard instance. Must not be null.
*/
protected abstract IWorkbenchWizard instanciateWizard(IAction action);
/* (non-Javadoc)
* @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
*/
public void selectionChanged(IAction action, ISelection selection) {
// pass
}
}

View File

@@ -105,8 +105,6 @@ public class NewProjectWizard extends Wizard implements INewWizard {
SdkConstants.FD_LAYOUT + AndroidConstants.WS_SEP;
private static final String VALUES_DIRECTORY =
SdkConstants.FD_VALUES + AndroidConstants.WS_SEP;
private static final String GEN_SRC_DIRECTORY =
SdkConstants.FD_GEN_SOURCES + AndroidConstants.WS_SEP;
private static final String TEMPLATES_DIRECTORY = "templates/"; //$NON-NLS-1$
private static final String TEMPLATE_MANIFEST = TEMPLATES_DIRECTORY
@@ -343,20 +341,15 @@ public class NewProjectWizard extends Wizard implements INewWizard {
// Create folders in the project if they don't already exist
addDefaultDirectories(project, AndroidConstants.WS_ROOT, DEFAULT_DIRECTORIES, monitor);
String[] sourceFolders = new String[] {
(String) parameters.get(PARAM_SRC_FOLDER),
GEN_SRC_DIRECTORY
};
addDefaultDirectories(project, AndroidConstants.WS_ROOT, sourceFolders, monitor);
String[] sourceFolder = new String[] { (String) parameters.get(PARAM_SRC_FOLDER) };
addDefaultDirectories(project, AndroidConstants.WS_ROOT, sourceFolder, monitor);
// Create the resource folders in the project if they don't already exist.
addDefaultDirectories(project, RES_DIRECTORY, RES_DIRECTORIES, monitor);
// Setup class path
IJavaProject javaProject = JavaCore.create(project);
for (String sourceFolder : sourceFolders) {
setupSourceFolder(javaProject, sourceFolder, monitor);
}
setupSourceFolder(javaProject, sourceFolder[0], monitor);
if (((Boolean) parameters.get(PARAM_IS_NEW_PROJECT)).booleanValue()) {
// Create files in the project if they don't already exist
@@ -366,7 +359,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
addIcon(project, monitor);
// Create the default package components
addSampleCode(project, sourceFolders[0], parameters, stringDictionary, monitor);
addSampleCode(project, sourceFolder[0], parameters, stringDictionary, monitor);
// add the string definition file if needed
if (stringDictionary.size() > 0) {
@@ -378,8 +371,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
monitor);
}
Sdk.getCurrent().setProject(project, (IAndroidTarget) parameters.get(PARAM_SDK_TARGET),
null /* apkConfigMap*/);
Sdk.getCurrent().setProject(project, (IAndroidTarget) parameters.get(PARAM_SDK_TARGET));
// Fix the project to make sure all properties are as expected.
// Necessary for existing projects and good for new ones to.

View File

@@ -148,11 +148,8 @@ public class AndroidConstants {
/** The old common plug-in ID. Please do not use for new features. */
public static final String COMMON_PLUGIN_ID = "com.android.ide.eclipse.common"; //$NON-NLS-1$
/** aapt marker error when running the compile command */
public final static String MARKER_AAPT_COMPILE = COMMON_PLUGIN_ID + ".aaptProblem"; //$NON-NLS-1$
/** aapt marker error when running the package command */
public final static String MARKER_AAPT_PACKAGE = COMMON_PLUGIN_ID + ".aapt2Problem"; //$NON-NLS-1$
/** aapt marker error. */
public final static String MARKER_AAPT = COMMON_PLUGIN_ID + ".aaptProblem"; //$NON-NLS-1$
/** XML marker error. */
public final static String MARKER_XML = COMMON_PLUGIN_ID + ".xmlProblem"; //$NON-NLS-1$

View File

@@ -19,7 +19,6 @@ package com.android.ide.eclipse.editors;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.sdk.AndroidTargetData;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
import com.android.ide.eclipse.editors.uimodel.UiElementNode;
import com.android.sdklib.IAndroidTarget;
@@ -98,9 +97,8 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang
private StructuredTextEditor mTextEditor;
/** Listener for the XML model from the StructuredEditor */
private XmlModelStateListener mXmlModelStateListener;
/** Listener to update the root node if the target of the file is changed because of a
* SDK location change or a project target change */
private ITargetChangeListener mTargetListener;
/** Listener to update the root node if the resource framework changes */
private Runnable mResourceRefreshListener;
/**
* Creates a form editor.
@@ -109,21 +107,15 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang
super();
ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
mTargetListener = new ITargetChangeListener() {
public void onProjectTargetChange(IProject changedProject) {
if (changedProject == getProject()) {
onTargetsLoaded();
}
}
public void onTargetsLoaded() {
mResourceRefreshListener = new Runnable() {
public void run() {
commitPages(false /* onSave */);
// recreate the ui root node always
initUiRootNode(true /*force*/);
}
};
AdtPlugin.getDefault().addTargetListener(mTargetListener);
AdtPlugin.getDefault().addResourceChangedListener(mResourceRefreshListener);
}
// ---- Abstract Methods ----
@@ -348,9 +340,9 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang
}
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
if (mTargetListener != null) {
AdtPlugin.getDefault().removeTargetListener(mTargetListener);
mTargetListener = null;
if (mResourceRefreshListener != null) {
AdtPlugin.getDefault().removeResourceChangedListener(mResourceRefreshListener);
mResourceRefreshListener = null;
}
super.dispose();

View File

@@ -313,7 +313,7 @@ public final class DescriptorsUtils {
*
* @param attributes The list of {@link AttributeDescriptor} to compare to.
* @param nsUri The URI of the attribute. Can be null if attribute has no namespace.
* See {@link SdkConstants#NS_RESOURCES} for a common value.
* See {@link AndroidConstants#NS_RESOURCES} for a common value.
* @param info The {@link AttributeInfo} to know whether it is included in the above list.
* @return True if this {@link AttributeInfo} is already present in
* the {@link AttributeDescriptor} list.

View File

@@ -21,7 +21,6 @@ import com.android.ide.eclipse.adt.sdk.AndroidTargetData;
import com.android.ide.eclipse.adt.sdk.LoadStatus;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.adt.sdk.AndroidTargetData.LayoutBridge;
import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
import com.android.ide.eclipse.common.resources.ResourceType;
import com.android.ide.eclipse.editors.IconFactory;
import com.android.ide.eclipse.editors.layout.LayoutEditor.UiEditorActions;
@@ -199,21 +198,13 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
private ProjectCallback mProjectCallback;
private ILayoutLog mLogger;
private boolean mNeedsXmlReload = false;
private boolean mNeedsRecompute = false;
private int mPlatformThemeCount = 0;
private boolean mDisableUpdates = false;
private boolean mActive = false;
/** Listener to update the root node if the target of the file is changed because of a
* SDK location change or a project target change */
private ITargetChangeListener mTargetListener = new ITargetChangeListener() {
public void onProjectTargetChange(IProject changedProject) {
if (changedProject == getLayoutEditor().getProject()) {
onTargetsLoaded();
}
}
public void onTargetsLoaded() {
private Runnable mFrameworkResourceChangeListener = new Runnable() {
public void run() {
// because the SDK changed we must reset the configured framework resource.
mConfiguredFrameworkRes = null;
@@ -237,7 +228,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
private final Runnable mConditionalRecomputeRunnable = new Runnable() {
public void run() {
if (mLayoutEditor.isGraphicalEditorActive()) {
if (mActive) {
recomputeLayout();
} else {
mNeedsRecompute = true;
@@ -262,7 +253,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
mMatchImage = factory.getIcon("match"); //$NON-NLS-1$
mErrorImage = factory.getIcon("error"); //$NON-NLS-1$
AdtPlugin.getDefault().addTargetListener(mTargetListener);
AdtPlugin.getDefault().addResourceChangedListener(mFrameworkResourceChangeListener);
}
// ------------------------------------
@@ -570,9 +561,10 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
@Override
public void dispose() {
if (mTargetListener != null) {
AdtPlugin.getDefault().removeTargetListener(mTargetListener);
mTargetListener = null;
if (mFrameworkResourceChangeListener != null) {
AdtPlugin.getDefault().removeResourceChangedListener(
mFrameworkResourceChangeListener);
mFrameworkResourceChangeListener = null;
}
LayoutReloadMonitor.getMonitor().removeListener(mEditedFile.getProject(), this);
@@ -1034,23 +1026,9 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
}
/**
* Callback for XML model changed. Only update/recompute the layout if the editor is visible
* Update the layout editor when the Xml model is changed.
*/
void onXmlModelChanged() {
if (mLayoutEditor.isGraphicalEditorActive()) {
doXmlReload(true /* force */);
recomputeLayout();
} else {
mNeedsXmlReload = true;
}
}
/**
* Actually performs the XML reload
* @see #onXmlModelChanged()
*/
private void doXmlReload(boolean force) {
if (force || mNeedsXmlReload) {
GraphicalViewer viewer = getGraphicalViewer();
// try to preserve the selection before changing the content
@@ -1063,7 +1041,10 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
selMan.setSelection(selection);
}
mNeedsXmlReload = false;
if (mLayoutEditor.isGraphicalEditorActive()) {
recomputeLayout();
} else {
mNeedsRecompute = true;
}
}
@@ -1667,9 +1648,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
/**
* Recomputes the layout with the help of layoutlib.
*/
@SuppressWarnings("deprecation")
void recomputeLayout() {
doXmlReload(false /* force */);
try {
// check that the resource exists. If the file is opened but the project is closed
// or deleted for some reason (changed from outside of eclipse), then this will
@@ -1784,47 +1763,20 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
if (themeIndex != -1) {
String theme = mThemeCombo.getItem(themeIndex);
// Compute the layout
UiElementPullParser parser = new UiElementPullParser(getModel());
Rectangle rect = getBounds();
ILayoutResult result = null;
if (bridge.apiLevel >= 3) {
// call the new api with proper theme differentiator and
// density/dpi support.
boolean isProjectTheme = themeIndex >= mPlatformThemeCount;
// FIXME pass the density/dpi from somewhere (resource config or skin).
result = bridge.bridge.computeLayout(parser,
iProject /* projectKey */,
rect.width, rect.height, 160, 160.f, 160.f,
theme, isProjectTheme,
mConfiguredProjectRes, frameworkResources, mProjectCallback,
mLogger);
} else if (bridge.apiLevel == 2) {
// api with boolean for separation of project/framework theme
boolean isProjectTheme = themeIndex >= mPlatformThemeCount;
result = bridge.bridge.computeLayout(parser,
iProject /* projectKey */,
rect.width, rect.height, theme, isProjectTheme,
mConfiguredProjectRes, frameworkResources, mProjectCallback,
mLogger);
} else {
// oldest api with no density/dpi, and project theme boolean mixed
// into the theme name.
// change the string if it's a custom theme to make sure we can
// differentiate them
if (themeIndex >= mPlatformThemeCount) {
theme = "*" + theme; //$NON-NLS-1$
}
result = bridge.bridge.computeLayout(parser,
// Compute the layout
UiElementPullParser parser = new UiElementPullParser(getModel());
Rectangle rect = getBounds();
ILayoutResult result = bridge.bridge.computeLayout(parser,
iProject /* projectKey */,
rect.width, rect.height, theme,
mConfiguredProjectRes, frameworkResources, mProjectCallback,
mLogger);
}
// update the UiElementNode with the layout info.
if (result.getSuccess() == ILayoutResult.SUCCESS) {
@@ -1969,7 +1921,8 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
* Responds to a page change that made the Graphical editor page the activated page.
*/
void activated() {
if (mNeedsRecompute || mNeedsXmlReload) {
mActive = true;
if (mNeedsRecompute) {
recomputeLayout();
}
}
@@ -1978,7 +1931,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
* Responds to a page change that made the Graphical editor page the deactivated page
*/
void deactivated() {
// nothing to be done here for now.
mActive = false;
}
/**

View File

@@ -269,12 +269,8 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa
protected void pageChange(int newPageIndex) {
super.pageChange(newPageIndex);
if (mGraphicalEditor != null) {
if (newPageIndex == mGraphicalEditorIndex) {
if (mGraphicalEditor != null && newPageIndex == mGraphicalEditorIndex) {
mGraphicalEditor.activated();
} else {
mGraphicalEditor.deactivated();
}
}
}
@@ -282,12 +278,8 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa
public void partActivated(IWorkbenchPart part) {
if (part == this) {
if (mGraphicalEditor != null) {
if (getActivePage() == mGraphicalEditorIndex) {
if (mGraphicalEditor != null && getActivePage() == mGraphicalEditorIndex) {
mGraphicalEditor.activated();
} else {
mGraphicalEditor.deactivated();
}
}
}
}
@@ -342,15 +334,15 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa
// ---- Local Methods ----
/**
* Returns true if the Graphics editor page is visible. This <b>must</b> be
* called from the UI thread.
* Returns true if the Graphics editor page is visible.
* This <b>must</b> be called from the UI thread.
*/
boolean isGraphicalEditorActive() {
IWorkbenchPartSite workbenchSite = getSite();
IWorkbenchPage workbenchPage = workbenchSite.getPage();
// check if the editor is visible in the workbench page
if (workbenchPage.isPartVisible(this) && workbenchPage.getActiveEditor() == this) {
if (workbenchPage.isPartVisible(this)) {
// and then if the page of the editor is visible (not to be confused with
// the workbench page)
return mGraphicalEditorIndex == getActivePage();

View File

@@ -195,8 +195,6 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider {
overrides.put("*/permission", ListAttributeDescriptor.class); //$NON-NLS-1$
overrides.put("*/targetPackage", PackageAttributeDescriptor.class); //$NON-NLS-1$
overrides.put("uses-library/name", ListAttributeDescriptor.class); //$NON-NLS-1$
overrides.put("action,category,uses-permission/" + ANDROID_NAME_ATTR, //$NON-NLS-1$
ListAttributeDescriptor.class);
overrides.put("application/" + ANDROID_NAME_ATTR, ApplicationAttributeDescriptor.class); //$NON-NLS-1$

View File

@@ -16,12 +16,12 @@
package com.android.ide.eclipse.editors.manifest.descriptors;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor;
import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode;
import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode.IPostTypeCreationAction;
import com.android.ide.eclipse.editors.uimodel.UiAttributeNode;
import com.android.ide.eclipse.editors.uimodel.UiElementNode;
import com.android.sdklib.SdkConstants;
/**
* Describes an XML attribute representing a class name.

View File

@@ -17,7 +17,6 @@
package com.android.ide.eclipse.editors.ui.tree;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
import com.android.ide.eclipse.editors.AndroidEditor;
import com.android.ide.eclipse.editors.IconFactory;
import com.android.ide.eclipse.editors.descriptors.ElementDescriptor;
@@ -27,7 +26,6 @@ import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener;
import com.android.ide.eclipse.editors.uimodel.UiDocumentNode;
import com.android.ide.eclipse.editors.uimodel.UiElementNode;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
@@ -287,21 +285,13 @@ public final class UiTreeBlock extends MasterDetailsBlock implements ICommitXml
}
};
/** Listener to update the root node if the target of the file is changed because of a
* SDK location change or a project target change */
final ITargetChangeListener targetListener = new ITargetChangeListener() {
public void onProjectTargetChange(IProject changedProject) {
if (changedProject == mEditor.getProject()) {
onTargetsLoaded();
}
}
public void onTargetsLoaded() {
final Runnable resourceRefreshListener = new Runnable() {
public void run() {
// If a details part has been created, we need to "refresh" it too.
if (mDetailsPart != null) {
// The details part does not directly expose access to its internal
// page book. Instead it is possible to resize the page book to 0 and then
// back to its original value, which has the side effect of removing all
// back to its original value, which as the side effect of removing all
// existing cached pages.
int limit = mDetailsPart.getPageLimit();
mDetailsPart.setPageLimit(0);
@@ -316,7 +306,7 @@ public final class UiTreeBlock extends MasterDetailsBlock implements ICommitXml
changeRootAndDescriptors(mUiRootNode, mDescriptorFilters, false /* refresh */);
// Listen on resource framework changes to refresh the tree
AdtPlugin.getDefault().addTargetListener(targetListener);
AdtPlugin.getDefault().addResourceChangedListener(resourceRefreshListener);
// Remove listeners when the tree widget gets disposed.
tree.addDisposeListener(new DisposeListener() {
@@ -328,7 +318,7 @@ public final class UiTreeBlock extends MasterDetailsBlock implements ICommitXml
node.removeUpdateListener(mUiRefreshListener);
mUiRootNode.removeUpdateListener(mUiEnableListener);
AdtPlugin.getDefault().removeTargetListener(targetListener);
AdtPlugin.getDefault().removeResourceChangedListener(resourceRefreshListener);
if (mClipboard != null) {
mClipboard.dispose();
mClipboard = null;
@@ -590,11 +580,7 @@ public final class UiTreeBlock extends MasterDetailsBlock implements ICommitXml
ui_node = ui_node.getUiParent()) {
segments.add(0, ui_node);
}
if (segments.size() > 0) {
mTreeViewer.setSelection(new TreeSelection(new TreePath(segments.toArray())));
} else {
mTreeViewer.setSelection(null);
}
}
}

View File

@@ -23,7 +23,6 @@ import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.ProjectChooserHelper;
import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor;
import com.android.ide.eclipse.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider;
import com.android.ide.eclipse.editors.menu.descriptors.MenuDescriptors;
import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration;
import com.android.ide.eclipse.editors.resources.configurations.ResourceQualifier;
@@ -82,7 +81,6 @@ class NewXmlFileCreationPage extends WizardPage {
private final String mXmlns;
private final String mDefaultAttrs;
private final String mDefaultRoot;
private final int mTargetApiLevel;
public TypeInfo(String uiName,
String tooltip,
@@ -90,8 +88,7 @@ class NewXmlFileCreationPage extends WizardPage {
Object rootSeed,
String defaultRoot,
String xmlns,
String defaultAttrs,
int targetApiLevel) {
String defaultAttrs) {
mUiName = uiName;
mResFolderType = resFolderType;
mTooltip = tooltip;
@@ -99,7 +96,6 @@ class NewXmlFileCreationPage extends WizardPage {
mDefaultRoot = defaultRoot;
mXmlns = xmlns;
mDefaultAttrs = defaultAttrs;
mTargetApiLevel = targetApiLevel;
}
/** Returns the UI name for the resource type. Unique. Never null. */
@@ -180,13 +176,6 @@ class NewXmlFileCreationPage extends WizardPage {
String getDefaultAttrs() {
return mDefaultAttrs;
}
/**
* The minimum API level required by the current SDK target to support this feature.
*/
public int getTargetApiLevel() {
return mTargetApiLevel;
}
}
/**
@@ -201,8 +190,7 @@ class NewXmlFileCreationPage extends WizardPage {
"LinearLayout", // default root
SdkConstants.NS_RESOURCES, // xmlns
"android:layout_width=\"wrap_content\"\n" + // default attributes
"android:layout_height=\"wrap_content\"",
1 // target API level
"android:layout_height=\"wrap_content\""
),
new TypeInfo("Values", // UI name
"An XML file with simple values: colors, strings, dimensions, etc.", // tooltip
@@ -210,8 +198,7 @@ class NewXmlFileCreationPage extends WizardPage {
ResourcesDescriptors.ROOT_ELEMENT, // root seed
null, // default root
null, // xmlns
null, // default attributes
1 // target API level
null // default attributes
),
new TypeInfo("Menu", // UI name
"An XML file that describes an menu.", // tooltip
@@ -219,17 +206,7 @@ class NewXmlFileCreationPage extends WizardPage {
MenuDescriptors.MENU_ROOT_ELEMENT, // root seed
null, // default root
SdkConstants.NS_RESOURCES, // xmlns
null, // default attributes
1 // target API level
),
new TypeInfo("Gadget Provider", // UI name
"An XML file that describes a gadget provider.", // tooltip
ResourceFolderType.XML, // folder type
AndroidTargetData.DESCRIPTOR_GADGET_PROVIDER, // root seed
null, // default root
SdkConstants.NS_RESOURCES, // xmlns
null, // default attributes
3 // target API level
null // default attributes
),
new TypeInfo("Preference", // UI name
"An XML file that describes preferences.", // tooltip
@@ -237,17 +214,15 @@ class NewXmlFileCreationPage extends WizardPage {
AndroidTargetData.DESCRIPTOR_PREFERENCES, // root seed
AndroidConstants.CLASS_PREFERENCE_SCREEN, // default root
SdkConstants.NS_RESOURCES, // xmlns
null, // default attributes
1 // target API level
null // default attributes
),
new TypeInfo("Searchable", // UI name
"An XML file that describes a searchable.", // tooltip
"An XML file that describes a searchable [TODO].", // tooltip
ResourceFolderType.XML, // folder type
AndroidTargetData.DESCRIPTOR_SEARCHABLE, // root seed
null, // default root
SdkConstants.NS_RESOURCES, // xmlns
null, // default attributes
1 // target API level
null // default attributes
),
new TypeInfo("Animation", // UI name
"An XML file that describes an animation.", // tooltip
@@ -262,14 +237,10 @@ class NewXmlFileCreationPage extends WizardPage {
},
"set", //$NON-NLS-1$ // default root
null, // xmlns
null, // default attributes
1 // target API level
null // default attributes
),
};
/** Number of columns in the grid layout */
final static int NUM_COL = 4;
/** Absolute destination folder root, e.g. "/res/" */
private static String sResFolderAbs = AndroidConstants.WS_RESOURCES + AndroidConstants.WS_SEP;
/** Relative destination folder root, e.g. "res/" */
@@ -319,7 +290,7 @@ class NewXmlFileCreationPage extends WizardPage {
initializeDialogUnits(parent);
composite.setLayout(new GridLayout(NUM_COL, false /*makeColumnsEqualWidth*/));
composite.setLayout(new GridLayout(3, false /*makeColumnsEqualWidth*/));
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
createProjectGroup(composite);
@@ -332,9 +303,8 @@ class NewXmlFileCreationPage extends WizardPage {
setControl(composite);
// Update state the first time
initializeFromSelection(mInitialSelection);
initializeRootValues();
enableTypesBasedOnApi();
initializeFromSelection(mInitialSelection);
validatePage();
}
@@ -448,35 +418,17 @@ class NewXmlFileCreationPage extends WizardPage {
new Label(parent, SWT.NONE);
}
/**
* Pads the parent with empty cells to match the number of columns of the parent grid.
*
* @param parent A grid layout with NUM_COL columns
* @param col The current number of columns used.
* @return 0, the new number of columns used, for convenience.
*/
private int padWithEmptyCells(Composite parent, int col) {
for (; col < NUM_COL; ++col) {
emptyCell(parent);
}
col = 0;
return col;
}
/**
* Creates the project & filename fields.
* <p/>
* The parent must be a GridLayout with NUM_COL colums.
* The parent must be a GridLayout with 3 colums.
*/
private void createProjectGroup(Composite parent) {
int col = 0;
// project name
String tooltip = "The Android Project where the new resource file will be created.";
Label label = new Label(parent, SWT.NONE);
label.setText("Project");
label.setToolTipText(tooltip);
++col;
mProjectTextField = new Text(parent, SWT.BORDER);
mProjectTextField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
@@ -486,7 +438,6 @@ class NewXmlFileCreationPage extends WizardPage {
onProjectFieldUpdated();
}
});
++col;
mProjectBrowseButton = new Button(parent, SWT.NONE);
mProjectBrowseButton.setText("Browse...");
@@ -498,16 +449,12 @@ class NewXmlFileCreationPage extends WizardPage {
}
});
mProjectChooserHelper = new ProjectChooserHelper(parent.getShell());
++col;
col = padWithEmptyCells(parent, col);
// file name
tooltip = "The name of the resource file to create.";
label = new Label(parent, SWT.NONE);
label.setText("File");
label.setToolTipText(tooltip);
++col;
mFileNameTextField = new Text(parent, SWT.BORDER);
mFileNameTextField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
@@ -517,32 +464,31 @@ class NewXmlFileCreationPage extends WizardPage {
validatePage();
}
});
++col;
padWithEmptyCells(parent, col);
emptyCell(parent);
}
/**
* Creates the type field, {@link ConfigurationSelector} and the folder field.
* <p/>
* The parent must be a GridLayout with NUM_COL colums.
* The parent must be a GridLayout with 3 colums.
*/
private void createTypeGroup(Composite parent) {
// separator
Label label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
label.setLayoutData(newGridData(NUM_COL, GridData.GRAB_HORIZONTAL));
label.setLayoutData(newGridData(3, GridData.GRAB_HORIZONTAL));
// label before type radios
label = new Label(parent, SWT.NONE);
label.setText("What type of resource would you like to create?");
label.setLayoutData(newGridData(NUM_COL));
label.setLayoutData(newGridData(3));
// display the types on three columns of radio buttons.
emptyCell(parent);
Composite grid = new Composite(parent, SWT.NONE);
padWithEmptyCells(parent, 2);
emptyCell(parent);
grid.setLayout(new GridLayout(NUM_COL, true /*makeColumnsEqualWidth*/));
grid.setLayout(new GridLayout(3, true /*makeColumnsEqualWidth*/));
SelectionListener radioListener = new SelectionAdapter() {
@Override
@@ -555,27 +501,23 @@ class NewXmlFileCreationPage extends WizardPage {
};
int n = sTypes.length;
int num_lines = (n + NUM_COL/2) / NUM_COL;
for (int line = 0, k = 0; line < num_lines; line++) {
for (int i = 0; i < NUM_COL; i++, k++) {
if (k < n) {
TypeInfo type = sTypes[k];
int num_lines = n/3;
for (int line = 0; line < num_lines; line++) {
for (int i = 0; i < 3; i++) {
TypeInfo type = sTypes[line * 3 + i];
Button radio = new Button(grid, SWT.RADIO);
type.setWidget(radio);
radio.setSelection(false);
radio.setText(type.getUiName());
radio.setToolTipText(type.getTooltip());
radio.addSelectionListener(radioListener);
} else {
emptyCell(grid);
}
}
}
// label before configuration selector
label = new Label(parent, SWT.NONE);
label.setText("What type of resource configuration would you like?");
label.setLayoutData(newGridData(NUM_COL));
label.setLayoutData(newGridData(3));
// configuration selector
emptyCell(parent);
@@ -585,7 +527,6 @@ class NewXmlFileCreationPage extends WizardPage {
gd.heightHint = ConfigurationSelector.HEIGHT_HINT;
mConfigSelector.setLayoutData(gd);
mConfigSelector.setOnChangeListener(new onConfigSelectorUpdated());
emptyCell(parent);
// folder name
String tooltip = "The folder where the file will be generated, relative to the project.";
@@ -601,23 +542,25 @@ class NewXmlFileCreationPage extends WizardPage {
onWsFolderPathUpdated();
}
});
emptyCell(parent);
}
/**
* Creates the root element combo.
* <p/>
* The parent must be a GridLayout with NUM_COL colums.
* The parent must be a GridLayout with 3 colums.
*/
private void createRootGroup(Composite parent) {
// separator
Label label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
label.setLayoutData(newGridData(NUM_COL, GridData.GRAB_HORIZONTAL));
label.setLayoutData(newGridData(3, GridData.GRAB_HORIZONTAL));
// label before the root combo
String tooltip = "The root element to create in the XML file.";
label = new Label(parent, SWT.NONE);
label.setText("Select the root element for the XML file:");
label.setLayoutData(newGridData(NUM_COL));
label.setLayoutData(newGridData(3));
label.setToolTipText(tooltip);
// root combo
@@ -629,7 +572,7 @@ class NewXmlFileCreationPage extends WizardPage {
mRootElementCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mRootElementCombo.setToolTipText(tooltip);
padWithEmptyCells(parent, 2);
emptyCell(parent);
}
/**
@@ -747,13 +690,11 @@ class NewXmlFileCreationPage extends WizardPage {
// get the AndroidTargetData from the project
IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
AndroidTargetData data = Sdk.getCurrent().getTargetData(target);
ElementDescriptor descriptor = data.getDescriptorProvider(
(Integer)rootSeed).getDescriptor();
IDescriptorProvider provider = data.getDescriptorProvider((Integer)rootSeed);
ElementDescriptor descriptor = provider.getDescriptor();
if (descriptor != null) {
HashSet<ElementDescriptor> visited = new HashSet<ElementDescriptor>();
initRootElementDescriptor(roots, descriptor, visited);
}
// Sort alphabetically.
Collections.sort(roots);
@@ -802,7 +743,15 @@ class NewXmlFileCreationPage extends WizardPage {
}
if (found != mProject) {
changeProject(found);
mProject = found;
// update the Type with the new descriptors.
initializeRootValues();
// update the combo
updateRootCombo(getSelectedType());
validatePage();
}
}
@@ -812,19 +761,8 @@ class NewXmlFileCreationPage extends WizardPage {
private void onProjectBrowse() {
IJavaProject p = mProjectChooserHelper.chooseJavaProject(mProjectTextField.getText());
if (p != null) {
changeProject(p.getProject());
mProject = p.getProject();
mProjectTextField.setText(mProject.getName());
}
}
/**
* Changes mProject to the given new project and update the UI accordingly.
*/
private void changeProject(IProject newProject) {
mProject = newProject;
// enable types based on new API level
enableTypesBasedOnApi();
// update the Type with the new descriptors.
initializeRootValues();
@@ -834,6 +772,7 @@ class NewXmlFileCreationPage extends WizardPage {
validatePage();
}
}
/**
* Callback called when the Folder text field is changed, either programmatically
@@ -1046,26 +985,6 @@ class NewXmlFileCreationPage extends WizardPage {
}
}
/**
* Helper method to enable the type radio buttons depending on the current API level.
* <p/>
* A type radio button is enabled either if:
* - if mProject is null, API level 1 is considered valid
* - if mProject is !null, the project->target->API must be >= to the type's API level.
*/
private void enableTypesBasedOnApi() {
IAndroidTarget target = mProject != null ? Sdk.getCurrent().getTarget(mProject) : null;
int currentApiLevel = 1;
if (target != null) {
currentApiLevel = target.getApiVersionNumber();
}
for (TypeInfo type : sTypes) {
type.getWidget().setEnabled(type.getTargetApiLevel() <= currentApiLevel);
}
}
/**
* Validates the fields, displays errors and warnings.
* Enables the finish button if there are no errors.
@@ -1098,22 +1017,6 @@ class NewXmlFileCreationPage extends WizardPage {
}
}
// -- validate type API level
if (error == null) {
IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
int currentApiLevel = 1;
if (target != null) {
currentApiLevel = target.getApiVersionNumber();
}
TypeInfo type = getSelectedType();
if (type.getTargetApiLevel() > currentApiLevel) {
error = "The API level of the selected type (e.g. gadget, etc.) is not " +
"compatible with the API level of the project.";
}
}
// -- validate folder configuration
if (error == null) {
ConfigurationState state = mConfigSelector.getState();

View File

@@ -53,9 +53,6 @@ public final class XmlDescriptors implements IDescriptorProvider {
/** The root document descriptor for preferences. */
private DocumentDescriptor mPrefDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
/** The root document descriptor for gadget provider. */
private DocumentDescriptor mGadgetDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
/** @return the root descriptor for both searchable and preferences. */
public DocumentDescriptor getDescriptor() {
return mDescriptor;
@@ -75,11 +72,6 @@ public final class XmlDescriptors implements IDescriptorProvider {
return mPrefDescriptor;
}
/** @return the root descriptor for gadget providers. */
public DocumentDescriptor getGadgetDescriptor() {
return mGadgetDescriptor;
}
public IDescriptorProvider getSearchableProvider() {
return new IDescriptorProvider() {
public ElementDescriptor getDescriptor() {
@@ -104,18 +96,6 @@ public final class XmlDescriptors implements IDescriptorProvider {
};
}
public IDescriptorProvider getGadgetProvider() {
return new IDescriptorProvider() {
public ElementDescriptor getDescriptor() {
return mGadgetDescriptor;
}
public ElementDescriptor[] getRootElementDescriptors() {
return mGadgetDescriptor.getChildren();
}
};
}
/**
* Updates the document descriptor.
* <p/>
@@ -123,13 +103,11 @@ public final class XmlDescriptors implements IDescriptorProvider {
* all at once.
*
* @param searchableStyleMap The map style=>attributes for <searchable> from the attrs.xml file
* @param gadgetStyleMap The map style=>attributes for <gadget-provider> from the attrs.xml file
* @param prefs The list of non-group preference descriptions
* @param prefGroups The list of preference group descriptions
*/
public synchronized void updateDescriptors(
Map<String, DeclareStyleableInfo> searchableStyleMap,
Map<String, DeclareStyleableInfo> gadgetStyleMap,
ViewClassInfo[] prefs, ViewClassInfo[] prefGroups) {
XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(
@@ -137,17 +115,12 @@ public final class XmlDescriptors implements IDescriptorProvider {
SdkConstants.NS_RESOURCES);
ElementDescriptor searchable = createSearchable(searchableStyleMap, xmlns);
ElementDescriptor gadget = createGadgetProviderInfo(gadgetStyleMap, xmlns);
ElementDescriptor preferences = createPreference(prefs, prefGroups, xmlns);
ArrayList<ElementDescriptor> list = new ArrayList<ElementDescriptor>();
if (searchable != null) {
list.add(searchable);
mSearchDescriptor.setChildren(new ElementDescriptor[]{ searchable });
}
if (gadget != null) {
list.add(gadget);
mGadgetDescriptor.setChildren(new ElementDescriptor[]{ gadget });
}
if (preferences != null) {
list.add(preferences);
mPrefDescriptor.setChildren(new ElementDescriptor[]{ preferences });
@@ -189,28 +162,6 @@ public final class XmlDescriptors implements IDescriptorProvider {
return searchable;
}
/**
* Returns the new ElementDescriptor for <gadget-provider>
*/
private ElementDescriptor createGadgetProviderInfo(
Map<String, DeclareStyleableInfo> gadgetStyleMap,
XmlnsAttributeDescriptor xmlns) {
if (gadgetStyleMap == null) {
return null;
}
ElementDescriptor gadget = createElement(gadgetStyleMap,
"GadgetProviderInfo", //$NON-NLS-1$ styleName
"gadget-provider", //$NON-NLS-1$ xmlName
"Gadget Provider", // uiName
null, // sdk url
xmlns, // extraAttribute
null, // childrenElements
false /* mandatory */ );
return gadget;
}
/**
* Returns a new ElementDescriptor constructed from the information given here
* and the javadoc & attributes extracted from the style map if any.

View File

@@ -22,13 +22,6 @@ if [ "-n" == "$1" ]; then
shift
fi
DIR="frameworks"
if [ "-s" == "$1" ]; then
shift
DIR="$1"
shift
fi
SRC="$1"
DST="$2"
@@ -43,7 +36,7 @@ function process() {
N=0
E=0
for i in `find -L "${SRC}/${DIR}" -name "*.java"`; do
for i in `find -L "${SRC}/frameworks" -name "*.java"`; do
if [ -f "$i" ]; then
# look for ^package (android.view.blah);$
PACKAGE=`sed -n '/^package [^ ;]\+; */{s/[^ ]* *\([^ ;]*\).*/\1/p;q}' "$i"`

View File

@@ -20,9 +20,9 @@ rem Set up prog to be the path of this script, including following symlinks,
rem and set up progdir to be the fully-qualified pathname of its directory.
set prog=%~f0
rem Change current directory and drive to where the script is, to avoid
rem issues with directories containing whitespaces.
cd /d %~dp0
rem Change current directory to where ddms is, to avoid issues with directories
rem containing whitespaces.
cd %~dp0
set jarfile=hierarchyviewer.jar
set frameworkdir=

View File

@@ -32,7 +32,6 @@ import java.net.Socket;
import java.util.Collections;
import java.util.Comparator;
import java.util.Stack;
import java.util.regex.Pattern;
public class ViewHierarchyLoader {
@SuppressWarnings("empty-statement")
@@ -111,8 +110,6 @@ public class ViewHierarchyLoader {
}
}
updateIndices(scene.getRoot());
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
} finally {
@@ -134,14 +131,6 @@ public class ViewHierarchyLoader {
return scene;
}
private static void updateIndices(ViewNode root) {
root.computeIndex();
for (ViewNode node : root.children) {
updateIndices(node);
}
}
private static int countFrontWhitespace(String line) {
int count = 0;
while (line.charAt(count) == ' ') {

View File

@@ -60,25 +60,22 @@ public class ViewHierarchyScene extends GraphScene<ViewNode, String> {
@Override
protected Widget attachNodeWidget(ViewNode node) {
Widget widget = createBox(node, node.name, node.id);
Widget widget = createBox(node.name, node.id);
widget.getActions().addAction(createSelectAction());
widget.getActions().addAction(moveAction);
widgetLayer.addChild(widget);
return widget;
}
private Widget createBox(ViewNode node, String nodeName, String id) {
final String shortName = getShortName(nodeName);
node.setShortName(shortName);
GradientWidget box = new GradientWidget(this, node);
private Widget createBox(String node, String id) {
Widget box = new GradientWidget(this);
box.setLayout(LayoutFactory.createVerticalFlowLayout());
box.setBorder(BorderFactory.createLineBorder(2, Color.BLACK));
box.setOpaque(true);
LabelWidget label = new LabelWidget(this);
label.setFont(getDefaultFont().deriveFont(Font.PLAIN, 12.0f));
label.setLabel(shortName);
label.setLabel(getShortName(node));
label.setBorder(BorderFactory.createEmptyBorder(6, 6, 0, 6));
label.setAlignment(LabelWidget.Alignment.CENTER);
@@ -86,12 +83,10 @@ public class ViewHierarchyScene extends GraphScene<ViewNode, String> {
label = new LabelWidget(this);
label.setFont(getDefaultFont().deriveFont(Font.PLAIN, 10.0f));
label.setLabel(getAddress(nodeName));
label.setLabel(getAddress(node));
label.setBorder(BorderFactory.createEmptyBorder(3, 6, 0, 6));
label.setAlignment(LabelWidget.Alignment.CENTER);
box.addressWidget = label;
box.addChild(label);
label = new LabelWidget(this);
@@ -141,7 +136,7 @@ public class ViewHierarchyScene extends GraphScene<ViewNode, String> {
connection.setTargetAnchor(AnchorFactory.createRectangularAnchor(target));
}
private static class GradientWidget extends Widget implements ViewNode.StateListener {
private static class GradientWidget extends Widget {
public static final GradientPaint BLUE_EXPERIENCE = new GradientPaint(
new Point2D.Double(0, 0),
new Color(168, 204, 241),
@@ -182,28 +177,15 @@ public class ViewHierarchyScene extends GraphScene<ViewNode, String> {
new Color(129, 138, 155),
new Point2D.Double(0, 1),
new Color(58, 66, 82));
public static final GradientPaint NIGHT_GRAY_VERY_LIGHT = new GradientPaint(
new Point2D.Double(0, 0),
new Color(129, 138, 155, 60),
new Point2D.Double(0, 1),
new Color(58, 66, 82, 60));
private static Color UNSELECTED = Color.BLACK;
private static Color SELECTED = Color.WHITE;
private final ViewNode node;
private LabelWidget addressWidget;
private boolean isSelected = false;
private final GradientPaint selectedGradient = MAC_OSX_SELECTED;
private final GradientPaint filteredGradient = RED_XP;
private final GradientPaint focusGradient = NIGHT_GRAY_VERY_LIGHT;
private GradientPaint gradient = MAC_OSX_SELECTED;
public GradientWidget(ViewHierarchyScene scene, ViewNode node) {
public GradientWidget(ViewHierarchyScene scene) {
super(scene);
this.node = node;
node.setStateListener(this);
}
@Override
@@ -211,12 +193,8 @@ public class ViewHierarchyScene extends GraphScene<ViewNode, String> {
super.notifyStateChanged(previous, state);
isSelected = state.isSelected() || state.isFocused() || state.isWidgetFocused();
pickChildrenColor();
}
private void pickChildrenColor() {
for (Widget child : getChildren()) {
child.setForeground(isSelected || node.filtered ? SELECTED : UNSELECTED);
child.setForeground(isSelected ? SELECTED : UNSELECTED);
}
repaint();
@@ -230,33 +208,12 @@ public class ViewHierarchyScene extends GraphScene<ViewNode, String> {
Rectangle bounds = getBounds();
if (!isSelected) {
if (!node.filtered) {
if (!node.hasFocus) {
g2.setColor(Color.WHITE);
} else {
g2.setPaint(new GradientPaint(bounds.x, bounds.y,
focusGradient.getColor1(), bounds.x, bounds.x + bounds.height,
focusGradient.getColor2()));
}
} else {
g2.setPaint(new GradientPaint(bounds.x, bounds.y, filteredGradient.getColor1(),
bounds.x, bounds.x + bounds.height, filteredGradient.getColor2()));
}
} else {
g2.setPaint(new GradientPaint(bounds.x, bounds.y, selectedGradient.getColor1(),
bounds.x, bounds.x + bounds.height, selectedGradient.getColor2()));
g2.setPaint(new GradientPaint(bounds.x, bounds.y, gradient.getColor1(),
bounds.x, bounds.x + bounds.height, gradient.getColor2()));
}
g2.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
public void nodeStateChanged(ViewNode node) {
pickChildrenColor();
}
public void nodeIndexChanged(ViewNode node) {
if (addressWidget != null) {
addressWidget.setLabel("#" + node.index + addressWidget.getLabel());
}
}
}
}

View File

@@ -17,6 +17,7 @@
package com.android.hierarchyviewer.scene;
import com.android.ddmlib.Device;
import com.android.hierarchyviewer.device.Configuration;
import com.android.hierarchyviewer.device.Window;
import com.android.hierarchyviewer.device.DeviceBridge;

View File

@@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public class ViewNode {
public String id;
@@ -53,14 +52,7 @@ public class ViewNode {
public boolean willNotDraw;
public boolean hasMargins;
boolean hasFocus;
int index;
public boolean decoded;
public boolean filtered;
private String shortName;
private StateListener listener;
void decode() {
id = namedProperties.get("mID").value;
@@ -81,7 +73,6 @@ public class ViewNode {
marginBottom = getInt("layout_bottomMargin", Integer.MIN_VALUE);
baseline = getInt("getBaseline()", 0);
willNotDraw = getBoolean("willNotDraw()", false);
hasFocus = getBoolean("hasFocus()", false);
hasMargins = marginLeft != Integer.MIN_VALUE &&
marginRight != Integer.MIN_VALUE &&
@@ -115,28 +106,6 @@ public class ViewNode {
return defaultValue;
}
public void filter(Pattern pattern) {
if (pattern == null || pattern.pattern().length() == 0) {
filtered = false;
} else {
filtered = pattern.matcher(shortName).find() || pattern.matcher(id).find();
}
listener.nodeStateChanged(this);
}
void computeIndex() {
index = parent == null ? 0 : parent.children.indexOf(this);
listener.nodeIndexChanged(this);
}
void setShortName(String shortName) {
this.shortName = shortName;
}
void setStateListener(StateListener listener) {
this.listener = listener;
}
@SuppressWarnings({"StringEquality"})
@Override
public boolean equals(Object obj) {
@@ -195,9 +164,4 @@ public class ViewNode {
return hash;
}
}
interface StateListener {
void nodeStateChanged(ViewNode node);
void nodeIndexChanged(ViewNode node);
}
}

View File

@@ -76,9 +76,6 @@ import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.JTree;
import javax.swing.Box;
import javax.swing.JTextField;
import javax.swing.text.Document;
import javax.swing.text.BadLocationException;
import javax.swing.tree.TreePath;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.event.ChangeEvent;
@@ -87,8 +84,6 @@ import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;
import javax.swing.table.DefaultTableModel;
import java.awt.image.BufferedImage;
import java.awt.BorderLayout;
@@ -110,8 +105,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.concurrent.ExecutionException;
public class Workspace extends JFrame {
@@ -163,8 +156,6 @@ public class Workspace extends JFrame {
private JTable windows;
private JLabel minZoomLabel;
private JLabel maxZoomLabel;
private JTextField filterText;
private JLabel filterLabel;
public Workspace() {
super("Hierarchy Viewer");
@@ -322,33 +313,10 @@ public class Workspace extends JFrame {
graphViewButton.setSelected(true);
filterText = new JTextField(20);
filterText.putClientProperty("JComponent.sizeVariant", "small");
filterText.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
updateFilter(e);
}
public void removeUpdate(DocumentEvent e) {
updateFilter(e);
}
public void changedUpdate(DocumentEvent e) {
updateFilter(e);
}
});
filterLabel = new JLabel("Filter by class or id:");
filterLabel.putClientProperty("JComponent.sizeVariant", "small");
filterLabel.setBorder(BorderFactory.createEmptyBorder(0, 6, 0, 6));
leftSide.add(filterLabel);
leftSide.add(filterText);
minZoomLabel = new JLabel();
minZoomLabel.setText("20%");
minZoomLabel.putClientProperty("JComponent.sizeVariant", "small");
minZoomLabel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0));
minZoomLabel.setBorder(BorderFactory.createEmptyBorder(0, 6, 0, 0));
leftSide.add(minZoomLabel);
zoomSlider = new JSlider();
@@ -389,18 +357,12 @@ public class Workspace extends JFrame {
statusPanel.add(rightSide, BorderLayout.LINE_END);
hideStatusBarComponents();
return statusPanel;
}
private void hideStatusBarComponents() {
viewCountLabel.setVisible(false);
zoomSlider.setVisible(false);
minZoomLabel.setVisible(false);
maxZoomLabel.setVisible(false);
filterLabel.setVisible(false);
filterText.setVisible(false);
return statusPanel;
}
private JToolBar buildToolBar() {
@@ -551,7 +513,10 @@ public class Workspace extends JFrame {
}
private void toggleGraphView() {
showStatusBarComponents();
viewCountLabel.setVisible(true);
zoomSlider.setVisible(true);
minZoomLabel.setVisible(true);
maxZoomLabel.setVisible(true);
screenViewer.stop();
mainPanel.remove(pixelPerfectPanel);
@@ -561,15 +526,6 @@ public class Workspace extends JFrame {
repaint();
}
private void showStatusBarComponents() {
viewCountLabel.setVisible(true);
zoomSlider.setVisible(true);
minZoomLabel.setVisible(true);
maxZoomLabel.setVisible(true);
filterLabel.setVisible(true);
filterText.setVisible(true);
}
private void togglePixelPerfectView() {
if (pixelPerfectPanel == null) {
pixelPerfectPanel = buildPixelPerfectPanel();
@@ -578,7 +534,10 @@ public class Workspace extends JFrame {
screenViewer.start();
}
hideStatusBarComponents();
viewCountLabel.setVisible(false);
zoomSlider.setVisible(false);
minZoomLabel.setVisible(false);
maxZoomLabel.setVisible(false);
mainPanel.remove(mainSplitter);
mainPanel.add(pixelPerfectPanel, BorderLayout.CENTER);
@@ -643,7 +602,10 @@ public class Workspace extends JFrame {
graphViewButton.setEnabled(true);
pixelPerfectViewButton.setEnabled(true);
showStatusBarComponents();
viewCountLabel.setVisible(true);
zoomSlider.setVisible(true);
minZoomLabel.setVisible(true);
maxZoomLabel.setVisible(true);
}
sceneView = scene.createView();
@@ -814,7 +776,10 @@ public class Workspace extends JFrame {
pixelPerfectPanel = mainSplitter = null;
graphViewButton.setSelected(true);
hideStatusBarComponents();
viewCountLabel.setVisible(false);
zoomSlider.setVisible(false);
minZoomLabel.setVisible(false);
maxZoomLabel.setVisible(false);
saveMenuItem.setEnabled(false);
showDevicesMenuItem.setEnabled(false);
@@ -900,34 +865,6 @@ public class Workspace extends JFrame {
});
}
private void updateFilter(DocumentEvent e) {
final Document document = e.getDocument();
try {
updateFilteredNodes(document.getText(0, document.getLength()));
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
private void updateFilteredNodes(String filterText) {
final ViewNode root = scene.getRoot();
try {
final Pattern pattern = Pattern.compile(filterText, Pattern.CASE_INSENSITIVE);
filterNodes(pattern, root);
} catch (PatternSyntaxException e) {
filterNodes(null, root);
}
repaint();
}
private void filterNodes(Pattern pattern, ViewNode root) {
root.filter(pattern);
for (ViewNode node : root.children) {
filterNodes(pattern, node);
}
}
public void beginTask() {
progress.setVisible(true);
}

View File

@@ -113,7 +113,7 @@ knownTests=(
# system-wide tests
"framework frameworks/base/tests/FrameworkTest # com.android.frameworktest.AllTests com.android.frameworktest.tests #"
"android frameworks/base/tests/AndroidTests # AndroidTests com.android.unit_tests #"
"android frameworks/base/tests/AndroidTests com.android.unit_tests AndroidTests # #"
"smoke frameworks/base/tests/SmokeTest com.android.smoketest # com.android.smoketest.tests #"
"core frameworks/base/tests/CoreTests # android.core.CoreTests android.core #"
"libcore frameworks/base/tests/CoreTests # android.core.JavaTests android.core #"

View File

@@ -23,9 +23,9 @@ set prog=%~f0
rem Grab current directory before we change it
set workdir=%cd%
rem Change current directory and drive to where the script is, to avoid
rem issues with directories containing whitespaces.
cd /d %~dp0
rem Change current directory to where ddms is, to avoid issues with directories
rem containing whitespaces.
cd %~dp0
set jarfile=sdkmanager.jar
set frameworkdir=

View File

@@ -383,17 +383,13 @@ class Main {
*/
private void displayAvdList() {
try {
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
AvdManager avdManager = new AvdManager(mSdkManager, null /* sdklog */);
mSdkLog.printf("Available Android Virtual Devices:\n");
AvdInfo[] avds = avdManager.getAvds();
for (int index = 0 ; index < avds.length ; index++) {
AvdInfo info = avds[index];
if (index > 0) {
mSdkLog.printf("---------\n");
}
mSdkLog.printf(" Name: %s\n", info.getName());
int index = 1;
for (AvdInfo info : avdManager.getAvds()) {
mSdkLog.printf("[%d] %s\n", index, info.getName());
mSdkLog.printf(" Path: %s\n", info.getPath());
// get the target of the AVD
@@ -421,6 +417,8 @@ class Main {
if (sdcard != null) {
mSdkLog.printf(" Sdcard: %s\n", sdcard);
}
index++;
}
} catch (AndroidLocationException e) {
errorAndExit(e.getMessage());
@@ -501,7 +499,7 @@ class Main {
// Is it NNNxMMM?
if (!valid) {
valid = AvdManager.NUMERIC_SKIN_SIZE.matcher(skin).matches();
valid = skin.matches("[0-9]{2,}x[0-9]{2,}");
}
if (!valid) {

View File

@@ -103,8 +103,6 @@ public final class SdkConstants {
public final static String FD_ASSETS = "assets"; //$NON-NLS-1$
/** Default source folder name, i.e. "src" */
public final static String FD_SOURCES = "src"; //$NON-NLS-1$
/** Default generated source folder name, i.e. "gen" */
public final static String FD_GEN_SOURCES = "gen"; //$NON-NLS-1$
/** Default native library folder name inside the project, i.e. "libs"
* While the folder inside the .apk is "lib", we call that one libs because
* that's what we use in ant for both .jar and .so and we need to make the 2 development ways

View File

@@ -55,12 +55,6 @@ public final class AvdManager {
public final static String AVD_INI_IMAGES_1 = "image.sysdir.1";
public final static String AVD_INI_IMAGES_2 = "image.sysdir.2";
/**
* Pattern to match pixel-sized skin "names", e.g. "320x480".
*/
public final static Pattern NUMERIC_SKIN_SIZE = Pattern.compile("[0-9]{2,}x[0-9]{2,}");
private final static String USERDATA_IMG = "userdata.img";
private final static String CONFIG_INI = "config.ini";
private final static String SDCARD_IMG = "sdcard.img";
@@ -261,10 +255,6 @@ public final class AvdManager {
skinName = target.getDefaultSkin();
}
if (NUMERIC_SKIN_SIZE.matcher(skinName).matches()) {
// Skin name is an actual screen resolution, no skin.path
values.put(AVD_INI_SKIN_NAME, skinName);
} else {
// get the path of the skin (relative to the SDK)
// assume skin name is valid
String skinPath = getSkinRelativePath(skinName, target, log);
@@ -275,7 +265,6 @@ public final class AvdManager {
values.put(AVD_INI_SKIN_PATH, skinPath);
values.put(AVD_INI_SKIN_NAME, skinName);
}
if (sdcard != null) {
File sdcardFile = new File(sdcard);

View File

@@ -25,30 +25,24 @@ import java.util.Map.Entry;
* Helper class to read and write Apk Configuration into a {@link ProjectProperties} file.
*/
public class ApkConfigurationHelper {
/** Prefix for property names for config definition. This prevents having config named
* after other valid properties such as "target". */
final static String CONFIG_PREFIX = "apk-config-";
/**
* Reads the Apk Configurations from a {@link ProjectProperties} file and returns them as a map.
* <p/>If there are no defined configurations, the returned map will be empty.
* @return a map of apk configurations. The map contains (name, filter) where name is
* the name of the configuration (a-zA-Z0-9 only), and filter is the comma separated list of
* resource configuration to include in the apk (see aapt -c)
*/
public static Map<String, String> getConfigs(ProjectProperties properties) {
HashMap<String, String> configMap = new HashMap<String, String>();
// get the list of configs.
String configList = properties.getProperty(ProjectProperties.PROPERTY_APK_CONFIGS);
String configList = properties.getProperty(ProjectProperties.PROPERTY_CONFIGS);
if (configList != null) {
// this is a comma separated list
String[] configs = configList.split(","); //$NON-NLS-1$
// read the value of each config and store it in a map
for (String config : configs) {
config = config.trim();
String configValue = properties.getProperty(CONFIG_PREFIX + config);
String configValue = properties.getProperty(config);
if (configValue != null) {
configMap.put(config, configValue);
}
@@ -60,10 +54,6 @@ public class ApkConfigurationHelper {
/**
* Writes the Apk Configurations from a given map into a {@link ProjectProperties}.
* @param properties the {@link ProjectProperties} in which to store the apk configurations.
* @param configMap a map of apk configurations. The map contains (name, filter) where name is
* the name of the configuration (a-zA-Z0-9 only), and filter is the comma separated list of
* resource configuration to include in the apk (see aapt -c)
* @return true if the {@link ProjectProperties} contained Apk Configuration that were not
* present in the map.
*/
@@ -72,20 +62,17 @@ public class ApkConfigurationHelper {
// in case a config was removed.
// get the list of configs.
String configList = properties.getProperty(ProjectProperties.PROPERTY_APK_CONFIGS);
String configList = properties.getProperty(ProjectProperties.PROPERTY_CONFIGS);
boolean hasRemovedConfig = false;
if (configList != null) {
// this is a comma separated list
String[] configs = configList.split(","); //$NON-NLS-1$
boolean hasRemovedConfig = false;
for (String config : configs) {
config = config.trim();
if (configMap.containsKey(config) == false) {
hasRemovedConfig = true;
properties.removeProperty(CONFIG_PREFIX + config);
}
properties.removeProperty(config);
}
}
@@ -97,9 +84,9 @@ public class ApkConfigurationHelper {
sb.append(",");
}
sb.append(entry.getKey());
properties.setProperty(CONFIG_PREFIX + entry.getKey(), entry.getValue());
properties.setProperty(entry.getKey(), entry.getValue());
}
properties.setProperty(ProjectProperties.PROPERTY_APK_CONFIGS, sb.toString());
properties.setProperty(ProjectProperties.PROPERTY_CONFIGS, sb.toString());
return hasRemovedConfig;
}

View File

@@ -209,7 +209,7 @@ public class ProjectCreator {
}
// create the source folder and the java package folders.
String srcFolderPath = SdkConstants.FD_SOURCES + File.separator + packagePath;
final String srcFolderPath = SdkConstants.FD_SOURCES + File.separator + packagePath;
File sourceFolder = createDirs(projectFolder, srcFolderPath);
String javaTemplate = "java_file.template";
String activityFileName = activityName + ".java";
@@ -220,10 +220,6 @@ public class ProjectCreator {
installTemplate(javaTemplate, new File(sourceFolder, activityFileName),
keywords, target);
// create the generate source folder
srcFolderPath = SdkConstants.FD_GEN_SOURCES + File.separator + packagePath;
sourceFolder = createDirs(projectFolder, srcFolderPath);
// create other useful folders
File resourceFodler = createDirs(projectFolder, SdkConstants.FD_RESOURCES);
createDirs(projectFolder, SdkConstants.FD_OUTPUT);

View File

@@ -33,7 +33,7 @@ import java.util.Map.Entry;
public final class ProjectProperties {
/** The property name for the project target */
public final static String PROPERTY_TARGET = "target";
public final static String PROPERTY_APK_CONFIGS = "apk-configurations";
public final static String PROPERTY_CONFIGS = "configs";
public final static String PROPERTY_SDK = "sdk-location";
public static enum PropertyType {
@@ -98,19 +98,7 @@ public final class ProjectProperties {
// 1-------10--------20--------30--------40--------50--------60--------70--------80
COMMENT_MAP.put(PROPERTY_TARGET,
"# Project target.\n");
COMMENT_MAP.put(PROPERTY_APK_CONFIGS,
"# apk configurations. This property allows creation of APK files with limited\n" +
"# resources. For example, if your application contains many locales and\n" +
"# you wish to release multiple smaller apks instead of a large one, you can\n" +
"# define configuration to create apks with limited language sets.\n" +
"# Format is a comma separated list of configuration names. For each\n" +
"# configuration, a property will declare the resource configurations to\n" +
"# include. Example:\n" +
"# " + PROPERTY_APK_CONFIGS +"=european,northamerica\n" +
"# " + ApkConfigurationHelper.CONFIG_PREFIX + "european=en,fr,it,de,es\n" +
"# " + ApkConfigurationHelper.CONFIG_PREFIX + "northamerica=en,es\n");
COMMENT_MAP.put(PROPERTY_SDK,
"# location of the SDK. This is only used by Ant\n" +
COMMENT_MAP.put(PROPERTY_SDK, "# location of the SDK. This is only used by Ant\n" +
"# For customization when using a Version Control System, please read the\n" +
"# header note.\n");
}

View File

@@ -1,177 +0,0 @@
/*
* 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.sdkuilib;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
/**
* Edit dialog to create/edit APK configuration. The dialog displays 2 text fields for the config
* name and its filter.
*/
class ApkConfigEditDialog extends Dialog implements ModifyListener, VerifyListener {
private String mName;
private String mFilter;
private Text mNameField;
private Text mFilterField;
private Button mOkButton;
/**
* Creates an edit dialog with optional initial values for the name and filter.
* @param name optional value for the name. Can be null.
* @param filter optional value for the filter. Can be null.
* @param parentShell the parent shell.
*/
protected ApkConfigEditDialog(String name, String filter, Shell parentShell) {
super(parentShell);
mName = name;
mFilter = filter;
}
/**
* Returns the name of the config. This is only valid if the user clicked OK and {@link #open()}
* returned {@link Window#OK}
*/
public String getName() {
return mName;
}
/**
* Returns the filter for the config. This is only valid if the user clicked OK and
* {@link #open()} returned {@link Window#OK}
*/
public String getFilter() {
return mFilter;
}
@Override
protected Control createContents(Composite parent) {
Control control = super.createContents(parent);
mOkButton = getButton(IDialogConstants.OK_ID);
validateButtons();
return control;
}
@Override
protected Control createDialogArea(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout;
composite.setLayout(layout = new GridLayout(2, false));
layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
layout.horizontalSpacing = convertHorizontalDLUsToPixels(
IDialogConstants.HORIZONTAL_SPACING);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
Label l = new Label(composite, SWT.NONE);
l.setText("Name");
mNameField = new Text(composite, SWT.BORDER);
mNameField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mNameField.addVerifyListener(this);
if (mName != null) {
mNameField.setText(mName);
}
mNameField.addModifyListener(this);
l = new Label(composite, SWT.NONE);
l.setText("Filter");
mFilterField = new Text(composite, SWT.BORDER);
mFilterField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
if (mFilter != null) {
mFilterField.setText(mFilter);
}
mFilterField.addVerifyListener(this);
mFilterField.addModifyListener(this);
applyDialogFont(composite);
return composite;
}
/**
* Validates the OK button based on the content of the 2 text fields.
*/
private void validateButtons() {
mOkButton.setEnabled(mNameField.getText().trim().length() > 0 &&
mFilterField.getText().trim().length() > 0);
}
@Override
protected void okPressed() {
mName = mNameField.getText();
mFilter = mFilterField.getText().trim();
super.okPressed();
}
/**
* Callback for text modification in the 2 text fields.
*/
public void modifyText(ModifyEvent e) {
validateButtons();
}
/**
* Callback to ensure the content of the text field are proper.
*/
public void verifyText(VerifyEvent e) {
Text source = ((Text)e.getSource());
if (source == mNameField) {
// check for a-zA-Z0-9.
final String text = e.text;
final int len = text.length();
for (int i = 0 ; i < len; i++) {
char letter = text.charAt(i);
if (letter > 255 || Character.isLetterOrDigit(letter) == false) {
e.doit = false;
return;
}
}
} else if (source == mFilterField) {
// we can't validate the content as its typed, but we can at least ensure the characters
// are valid. Same as mNameFiled + the comma.
final String text = e.text;
final int len = text.length();
for (int i = 0 ; i < len; i++) {
char letter = text.charAt(i);
if (letter > 255 || (Character.isLetterOrDigit(letter) == false && letter != ',')) {
e.doit = false;
return;
}
}
}
}
}

View File

@@ -1,211 +0,0 @@
/*
* 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.sdkuilib;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* The APK Configuration widget is a table that is added to the given parent composite.
* <p/>
* To use, create it using {@link #ApkConfigWidget(Composite)} then
* call {@link #fillTable(Map) to set the initial list of configurations.
*/
public class ApkConfigWidget {
private final static int INDEX_NAME = 0;
private final static int INDEX_FILTER = 1;
private Table mApkConfigTable;
private Button mEditButton;
private Button mDelButton;
public ApkConfigWidget(final Composite parent) {
final Composite apkConfigComp = new Composite(parent, SWT.NONE);
apkConfigComp.setLayoutData(new GridData(GridData.FILL_BOTH));
apkConfigComp.setLayout(new GridLayout(2, false));
mApkConfigTable = new Table(apkConfigComp, SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER);
mApkConfigTable.setHeaderVisible(true);
mApkConfigTable.setLinesVisible(true);
GridData data = new GridData();
data.grabExcessVerticalSpace = true;
data.grabExcessHorizontalSpace = true;
data.horizontalAlignment = GridData.FILL;
data.verticalAlignment = GridData.FILL;
mApkConfigTable.setLayoutData(data);
// create the table columns
final TableColumn column0 = new TableColumn(mApkConfigTable, SWT.NONE);
column0.setText("Name");
column0.setWidth(100);
final TableColumn column1 = new TableColumn(mApkConfigTable, SWT.NONE);
column1.setText("Configuration");
column1.setWidth(100);
Composite buttonComp = new Composite(apkConfigComp, SWT.NONE);
buttonComp.setLayoutData(new GridData(GridData.FILL_VERTICAL));
GridLayout gl;
buttonComp.setLayout(gl = new GridLayout(1, false));
gl.marginHeight = gl.marginWidth = 0;
Button newButton = new Button(buttonComp, SWT.PUSH | SWT.FLAT);
newButton.setText("New...");
newButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mEditButton = new Button(buttonComp, SWT.PUSH | SWT.FLAT);
mEditButton.setText("Edit...");
mEditButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mDelButton = new Button(buttonComp, SWT.PUSH | SWT.FLAT);
mDelButton.setText("Delete");
mDelButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
newButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ApkConfigEditDialog dlg = new ApkConfigEditDialog(null /*name*/, null /*filter*/,
apkConfigComp.getShell());
if (dlg.open() == Dialog.OK) {
TableItem item = new TableItem(mApkConfigTable, SWT.NONE);
item.setText(INDEX_NAME, dlg.getName());
item.setText(INDEX_FILTER, dlg.getFilter());
onSelectionChanged();
}
}
});
mEditButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// get the current selection (single mode so we don't care about any item beyond
// index 0).
TableItem[] items = mApkConfigTable.getSelection();
if (items.length != 0) {
ApkConfigEditDialog dlg = new ApkConfigEditDialog(
items[0].getText(INDEX_NAME), items[0].getText(INDEX_FILTER),
apkConfigComp.getShell());
if (dlg.open() == Dialog.OK) {
items[0].setText(INDEX_NAME, dlg.getName());
items[0].setText(INDEX_FILTER, dlg.getFilter());
}
}
}
});
mDelButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// get the current selection (single mode so we don't care about any item beyond
// index 0).
int[] indices = mApkConfigTable.getSelectionIndices();
if (indices.length != 0) {
TableItem item = mApkConfigTable.getItem(indices[0]);
if (MessageDialog.openQuestion(parent.getShell(),
"Apk Configuration deletion",
String.format(
"Are you sure you want to delete configuration '%1$s'?",
item.getText(INDEX_NAME)))) {
// delete the item.
mApkConfigTable.remove(indices[0]);
onSelectionChanged();
}
}
}
});
// Add a listener to resize the column to the full width of the table
mApkConfigTable.addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
Rectangle r = mApkConfigTable.getClientArea();
column0.setWidth(r.width * 30 / 100); // 30%
column1.setWidth(r.width * 70 / 100); // 70%
}
});
// add a selection listener on the table, to enable/disable buttons.
mApkConfigTable.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
onSelectionChanged();
}
});
}
public void fillTable(Map<String, String> apkConfigMap) {
// get the names in a list so that we can sort them.
if (apkConfigMap != null) {
Set<String> keys = apkConfigMap.keySet();
String[] keyArray = keys.toArray(new String[keys.size()]);
Arrays.sort(keyArray);
for (String key : keyArray) {
TableItem item = new TableItem(mApkConfigTable, SWT.NONE);
item.setText(INDEX_NAME, key);
item.setText(INDEX_FILTER, apkConfigMap.get(key));
}
}
onSelectionChanged();
}
public Map<String, String> getApkConfigs() {
// go through all the items from the table and fill a new map
HashMap<String, String> map = new HashMap<String, String>();
TableItem[] items = mApkConfigTable.getItems();
for (TableItem item : items) {
map.put(item.getText(INDEX_NAME), item.getText(INDEX_FILTER));
}
return map;
}
/**
* Handles table selection changes.
*/
private void onSelectionChanged() {
if (mApkConfigTable.getSelectionCount() > 0) {
mEditButton.setEnabled(true);
mDelButton.setEnabled(true);
} else {
mEditButton.setEnabled(false);
mDelButton.setEnabled(false);
}
}
}

View File

@@ -48,57 +48,32 @@ import java.util.ArrayList;
*/
public class SdkTargetSelector {
private IAndroidTarget[] mTargets;
private final boolean mAllowSelection;
private final IAndroidTarget[] mTargets;
private final boolean mAllowMultipleSelection;
private SelectionListener mSelectionListener;
private Table mTable;
private Label mDescription;
private Composite mInnerGroup;
/**
* Creates a new SDK Target Selector.
*
* @param parent The parent composite where the selector will be added.
* @param targets The list of targets. This is <em>not</em> copied, the caller must not modify.
* Targets can be null or an empty array, in which case the table is disabled.
* @param allowMultipleSelection True if more than one SDK target can be selected at the same
* time.
*/
public SdkTargetSelector(Composite parent, IAndroidTarget[] targets,
boolean allowMultipleSelection) {
this(parent, targets, true /*allowSelection*/, allowMultipleSelection);
}
mTargets = targets;
/**
* Creates a new SDK Target Selector.
*
* @param parent The parent composite where the selector will be added.
* @param targets The list of targets. This is <em>not</em> copied, the caller must not modify.
* Targets can be null or an empty array, in which case the table is disabled.
* @param allowSelection True if selection is enabled.
* @param allowMultipleSelection True if more than one SDK target can be selected at the same
* time. Used only if allowSelection is true.
*/
public SdkTargetSelector(Composite parent, IAndroidTarget[] targets,
boolean allowSelection,
boolean allowMultipleSelection) {
// Layout has 1 column
mInnerGroup = new Composite(parent, SWT.NONE);
mInnerGroup.setLayout(new GridLayout());
mInnerGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
mInnerGroup.setFont(parent.getFont());
Composite group = new Composite(parent, SWT.NONE);
group.setLayout(new GridLayout());
group.setLayoutData(new GridData(GridData.FILL_BOTH));
group.setFont(parent.getFont());
mAllowSelection = allowSelection;
mAllowMultipleSelection = allowMultipleSelection;
int style = SWT.BORDER;
if (allowSelection) {
style |= SWT.CHECK | SWT.FULL_SELECTION;
}
if (!mAllowMultipleSelection) {
style |= SWT.SINGLE;
}
mTable = new Table(mInnerGroup, style);
mTable = new Table(group, SWT.CHECK | SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER);
mTable.setHeaderVisible(true);
mTable.setLinesVisible(false);
@@ -109,7 +84,7 @@ public class SdkTargetSelector {
data.verticalAlignment = GridData.FILL;
mTable.setLayoutData(data);
mDescription = new Label(mInnerGroup, SWT.WRAP);
mDescription = new Label(group, SWT.WRAP);
mDescription.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// create the table columns
@@ -118,27 +93,16 @@ public class SdkTargetSelector {
final TableColumn column1 = new TableColumn(mTable, SWT.NONE);
column1.setText("Vendor");
final TableColumn column2 = new TableColumn(mTable, SWT.NONE);
column2.setText("Version");
column2.setText("API Level");
final TableColumn column3 = new TableColumn(mTable, SWT.NONE);
column3.setText("API Level");
column3.setText("SDK");
adjustColumnsWidth(mTable, column0, column1, column2, column3);
setupSelectionListener(mTable);
setTargets(targets);
fillTable(mTable);
setupTooltip(mTable);
}
/**
* Returns the layout data of the inner composite widget that contains the target selector.
* By default the layout data is set to a {@link GridData} with a {@link GridData#FILL_BOTH}
* mode.
* <p/>
* This can be useful if you want to change the {@link GridData#horizontalSpan} for example.
*/
public Object getLayoutData() {
return mInnerGroup.getLayoutData();
}
/**
* Returns the list of known targets.
* <p/>
@@ -148,16 +112,6 @@ public class SdkTargetSelector {
return mTargets;
}
/**
* Changes the targets of the SDK Target Selector.
*
* @param targets The list of targets. This is <em>not</em> copied, the caller must not modify.
*/
public void setTargets(IAndroidTarget[] targets) {
mTargets = targets;
fillTable(mTable);
}
/**
* Sets a selection listener. Set it to null to remove it.
* The listener will be called <em>after</em> this table processed its selection
@@ -185,10 +139,6 @@ public class SdkTargetSelector {
* @return true if the target could be selected, false otherwise.
*/
public boolean setSelection(IAndroidTarget target) {
if (!mAllowSelection) {
return false;
}
boolean found = false;
boolean modified = false;
for (TableItem i : mTable.getItems()) {
@@ -274,10 +224,6 @@ public class SdkTargetSelector {
* double-clicked (aka "the default selection").
*/
private void setupSelectionListener(final Table table) {
if (!mAllowSelection) {
return;
}
// Add a selection listener that will check/uncheck items when they are double-clicked
table.addSelectionListener(new SelectionListener() {
/** Default selection means double-click on "most" platforms */
@@ -335,9 +281,6 @@ public class SdkTargetSelector {
* </ul>
*/
private void fillTable(final Table table) {
table.removeAll();
if (mTargets != null && mTargets.length > 0) {
table.setEnabled(true);
for (IAndroidTarget target : mTargets) {

View File

@@ -20,9 +20,9 @@ rem Set up prog to be the path of this script, including following symlinks,
rem and set up progdir to be the fully-qualified pathname of its directory.
set prog=%~f0
rem Change current directory and drive to where traceview.bat is, to avoid
rem issues with directories containing whitespaces.
cd /d %~dp0
rem Change current directory to where traceview is, to avoid issues with directories
rem containing whitespaces.
cd %~dp0
set jarfile=traceview.jar
set frameworkdir=