OSDN Git Service

Merge change I2cdb052a into eclair
authorAndroid (Google) Code Review <android-gerrit@google.com>
Tue, 29 Sep 2009 22:35:53 +0000 (18:35 -0400)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Tue, 29 Sep 2009 22:35:53 +0000 (18:35 -0400)
* changes:
  Import testrunner changes from puppetmaster to keep them in sync.

57 files changed:
apps/Development/res/layout/development_settings.xml
apps/Development/res/layout/package_list_item.xml [new file with mode: 0644]
apps/Development/res/values/strings.xml
apps/Development/src/com/android/development/AppPicker.java
apps/Development/src/com/android/development/DevelopmentSettings.java
apps/Development/src/com/android/development/PackageBrowser.java
apps/Development/src/com/android/development/PackageSummary.java
build/sdk.atree
ndk/build/toolchains/arm-eabi-4.2.1/setup.mk
ndk/docs/CHANGES.TXT
samples/JetBoy/src/com/example/android/jetboy/JetBoy.java
testrunner/test_defs.xml
tools/anttasks/src/com/android/ant/AndroidXPathFactory.java [deleted file]
tools/anttasks/src/com/android/ant/SetupTask.java
tools/anttasks/src/com/android/ant/XPathTask.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalEditorPart.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalLayoutEditor.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/IGraphicalLayoutEditor.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/model/UiClassAttributeNode.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/KeyboardStateQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NavigationMethodQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/PixelDensityQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenOrientationQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenRatioQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenSizeQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TextInputMethodQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TouchScreenQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/DeviceConfiguration.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutConfigsXsd.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceHandler.java [new file with mode: 0644]
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-configs.xsd
tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutConfisXsd.java
tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/config_sample.xml
tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/functests/layoutRendering/ApiDemosRenderingTest.java
tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/configurations/PixelDensityQualifierTest.java
tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java
tools/scripts/AndroidManifest.template
tools/scripts/AndroidManifest.tests.template
tools/scripts/iml.template [deleted file]
tools/scripts/ipr.template [deleted file]
tools/scripts/iws.template [deleted file]
tools/scripts/java_file.template
tools/scripts/java_tests_file.template
tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java
tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifest.java [moved from tools/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/ManifestConstants.java with 60% similarity]
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidXPathFactory.java

index 4f185aa..7bad3bb 100644 (file)
             android:layout_alignParentLeft="true"
             android:text="@string/development_settings_show_updates_text" />
 
+        <CheckBox android:id="@+id/compatibility_mode"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/show_updates"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_compatibility_mode_text" />
+
         <Spinner android:id="@+id/max_procs"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:layout_below="@id/show_updates"
+            android:layout_below="@id/compatibility_mode"
             android:layout_alignParentLeft="true" />
 
         <View android:id="@+id/separator2"
diff --git a/apps/Development/res/layout/package_list_item.xml b/apps/Development/res/layout/package_list_item.xml
new file mode 100644 (file)
index 0000000..6a0faee
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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:minHeight="?android:attr/listPreferredItemHeight"
+    android:orientation="vertical"
+    android:gravity="fill" >
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="horizontal"
+        android:paddingRight="6dip"
+        android:paddingLeft="6dip"
+        android:gravity="center_vertical" >
+    
+        <ImageView android:id="@+id/icon"
+            android:layout_width="@android:dimen/app_icon_size"
+            android:layout_height="@android:dimen/app_icon_size"
+            android:layout_marginLeft="5dip"
+            android:layout_marginRight="11dip"
+            android:layout_gravity="center_vertical"
+            android:scaleType="fitCenter"/>
+    
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content" >
+            <TextView android:id="@+id/name"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:textStyle="bold"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:layout_marginBottom="2dip" />
+            <TextView android:id="@+id/description"
+                android:layout_marginTop="-4dip"
+                android:layout_gravity="center_vertical|left"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingRight="4dip"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:textAppearance="?android:attr/textAppearanceSmall" />
+        </LinearLayout>
+    </LinearLayout>
+</LinearLayout>
index 21f15f6..ad70fbe 100644 (file)
@@ -77,6 +77,9 @@
     <string name="development_settings_always_finish_text">Immediately destroy activities</string>
     <string name="development_settings_show_load_text">Show running processes</string>
     <string name="development_settings_show_updates_text">Show screen updates</string>
+    <string name="development_settings_compatibility_mode_text">Disable compatibility mode</string>
+    <string name="development_settings_compatibility_mode_toast">Reboot required for
+            change to take effect.</string>
     <string name="development_settings_enable_gl_text">Enable OpenGL ES (reboot needed)</string>
     <string name="development_settings_allow_mock_location_text">Allow mock locations for testing</string>
     <string name="development_settings_wait_for_debugger_text">Wait for debugger</string>
index 693defb..28040c2 100644 (file)
 
 package com.android.development;
 
+import com.android.development.PackageBrowser.MyPackageInfo;
+
 import android.app.ActivityManagerNative;
 import android.app.ListActivity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.provider.Settings;
@@ -29,10 +32,12 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.view.LayoutInflater;
 import android.widget.BaseAdapter;
+import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
 
 import java.text.Collator;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -67,96 +72,67 @@ public class AppPicker extends ListActivity
     @Override
     protected void onListItemClick(ListView l, View v, int position, long id)
     {
-        ApplicationInfo app = mAdapter.appForPosition(position);
+        MyApplicationInfo app = mAdapter.itemForPosition(position);
         Intent intent = new Intent();
-        if (app != null) intent.setAction(app.packageName);
+        if (app.info != null) intent.setAction(app.info.packageName);
         setResult(RESULT_OK, intent);
         
-        /* This is a temporary fix for 824637 while it is blocked by 805226.  When 805226 is resolved, please remove this. */
         try {
             boolean waitForDebugger = Settings.System.getInt(
                     getContentResolver(), Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
             ActivityManagerNative.getDefault().setDebugApp(
-                    app != null ? app.packageName : null, waitForDebugger, true);
+                    app.info != null ? app.info.packageName : null, waitForDebugger, true);
         } catch (RemoteException ex) {
         }
         
         finish();
     }
 
-    private final class AppListAdapter extends BaseAdapter
-    {
-        public AppListAdapter(Context context)
-        {
-            mContext = context;
-            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
-            mList = context.getPackageManager().getInstalledApplications(0);
-            if (mList != null) {
-                Collections.sort(mList, sDisplayNameComparator);
-                mList.add(0, null);
-            }
-        }
+    class MyApplicationInfo {
+        ApplicationInfo info;
+        String label;
+    }
     
-        public ApplicationInfo appForPosition(int position)
-        {
-            if (mList == null) {
-                return null;
+    public class AppListAdapter extends ArrayAdapter<MyApplicationInfo> {
+        private List<MyApplicationInfo> mPackageInfoList = new ArrayList<MyApplicationInfo>();
+
+        public AppListAdapter(Context context) {
+            super(context, R.layout.package_list_item);
+            List<ApplicationInfo> pkgs = context.getPackageManager().getInstalledApplications(0);
+            for (int i=0; i<pkgs.size(); i++) {
+                MyApplicationInfo info = new MyApplicationInfo();
+                info.info = pkgs.get(i);
+                info.label = info.info.loadLabel(getPackageManager()).toString();
+                mPackageInfoList.add(info);
             }
-
-            return mList.get(position);
-        }
-
-        public int getCount()
-        {
-            return mList != null ? mList.size() : 0;
-        }
-
-        public Object getItem(int position)
-        {
-            return position;
-        }
-    
-        public long getItemId(int position)
-        {
-            return position;
+            Collections.sort(mPackageInfoList, sDisplayNameComparator);
+            MyApplicationInfo info = new MyApplicationInfo();
+            info.label = "(none)";
+            mPackageInfoList.add(0, info);
+            setSource(mPackageInfoList);
         }
     
-        public View getView(int position, View convertView, ViewGroup parent)
-        {
-            View view;
-            if (convertView == null) {
-                view = mInflater.inflate(
-                        android.R.layout.simple_list_item_1, parent, false);
+        @Override
+        public void bindView(View view, MyApplicationInfo info) {
+            ImageView icon = (ImageView)view.findViewById(R.id.icon);
+            TextView name = (TextView)view.findViewById(R.id.name);
+            TextView description = (TextView)view.findViewById(R.id.description);
+            name.setText(info.label);
+            if (info.info != null) {
+                icon.setImageDrawable(info.info.loadIcon(getPackageManager()));
+                description.setText(info.info.packageName);
             } else {
-                view = convertView;
+                icon.setImageDrawable(null);
+                description.setText("");
             }
-            bindView(view, mList.get(position));
-            return view;
-        }
-    
-        private final void bindView(View view, ApplicationInfo info)
-        {
-            TextView text = (TextView)view.findViewById(android.R.id.text1);
-    
-            text.setText(info != null ? info.packageName : "(none)");
         }
-    
-        protected final Context mContext;
-        protected final LayoutInflater mInflater;
-    
-        protected List<ApplicationInfo> mList;
-        
     }
 
-    private final static Comparator sDisplayNameComparator = new Comparator() {
+    private final static Comparator<MyApplicationInfo> sDisplayNameComparator
+            = new Comparator<MyApplicationInfo>() {
         public final int
-        compare(Object a, Object b)
-        {
-            CharSequence  sa = ((ApplicationInfo) a).packageName;
-            CharSequence  sb = ((ApplicationInfo) b).packageName;
-
-            return collator.compare(sa, sb);
+        compare(MyApplicationInfo a, MyApplicationInfo b) {
+            return collator.compare(a.label, b.label);
         }
 
         private final Collator   collator = Collator.getInstance();
index 3b4848a..9cb6fc6 100644 (file)
@@ -38,6 +38,7 @@ import android.widget.Button;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
 import android.widget.Spinner;
+import android.widget.Toast;
 import android.widget.AdapterView.OnItemSelectedListener;
 
 import java.io.FileInputStream;
@@ -58,6 +59,7 @@ public class DevelopmentSettings extends Activity {
     private CheckBox mShowBackgroundCB;
     private CheckBox mShowSleepCB;
     private CheckBox mShowXmppCB;
+    private CheckBox mCompatibilityModeCB;
     private Spinner mMaxProcsSpinner;
     private Spinner mWindowAnimationScaleSpinner;
     private Spinner mTransitionAnimationScaleSpinner;
@@ -69,6 +71,7 @@ public class DevelopmentSettings extends Activity {
     private int mProcessLimit;
     private boolean mShowSleep;
     private boolean mShowXmpp;
+    private boolean mCompatibilityMode;
     private AnimationScaleSelectedListener mWindowAnimationScale
             = new AnimationScaleSelectedListener(0);
     private AnimationScaleSelectedListener mTransitionAnimationScale
@@ -106,6 +109,8 @@ public class DevelopmentSettings extends Activity {
         mShowSleepCB.setOnClickListener(mShowSleepClicked);
         mShowXmppCB = (CheckBox)findViewById(R.id.show_xmpp);
         mShowXmppCB.setOnClickListener(mShowXmppClicked);
+        mCompatibilityModeCB = (CheckBox)findViewById(R.id.compatibility_mode);
+        mCompatibilityModeCB.setOnClickListener(mCompatibilityModeClicked);
         mMaxProcsSpinner = (Spinner)findViewById(R.id.max_procs);
         mMaxProcsSpinner.setOnItemSelectedListener(mMaxProcsChanged);
         ArrayAdapter<String> adapter = new ArrayAdapter<String>(
@@ -168,7 +173,8 @@ public class DevelopmentSettings extends Activity {
         updateSharedOptions();
         updateFlingerOptions();
         updateSleepOptions();
-        updateXmppOptions();        
+        updateXmppOptions();
+        updateCompatibilityOptions();
 
         try {
             FileInputStream  in = new FileInputStream( FONT_HINTING_FILE );
@@ -235,6 +241,17 @@ public class DevelopmentSettings extends Activity {
                 Settings.System.SHOW_PROCESSES, 0) != 0);
     }
 
+    private void writeCompatibilityOptions() {
+        Settings.System.putInt(getContentResolver(),
+                Settings.System.COMPATIBILITY_MODE, mCompatibilityMode ? 0 : 1);
+    }
+
+    private void updateCompatibilityOptions() {
+        mCompatibilityMode = Settings.System.getInt(
+            getContentResolver(), Settings.System.COMPATIBILITY_MODE, 1) == 0;
+        mCompatibilityModeCB.setChecked(mCompatibilityMode);
+    }
+
     private void updateFlingerOptions() {
         // magic communication with surface flinger.
         try {
@@ -332,6 +349,19 @@ public class DevelopmentSettings extends Activity {
         }
     };
 
+    private View.OnClickListener mCompatibilityModeClicked =
+        new View.OnClickListener() {
+    public void onClick(View v) {
+        mCompatibilityMode = ((CheckBox)v).isChecked();
+        writeCompatibilityOptions();
+        updateCompatibilityOptions();
+        Toast toast = Toast.makeText(DevelopmentSettings.this,
+                R.string.development_settings_compatibility_mode_toast,
+                Toast.LENGTH_LONG);
+        toast.show();
+    }
+};
+
     private View.OnClickListener mShowLoadClicked = new View.OnClickListener() {
         public void onClick(View v) {
             boolean value = ((CheckBox)v).isChecked();
index e4c233f..689183d 100644 (file)
@@ -31,27 +31,38 @@ import android.os.Handler;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
 
 import java.text.Collator;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-public class PackageBrowser extends ListActivity
-{
+public class PackageBrowser extends ListActivity {
+    static class MyPackageInfo {
+        PackageInfo info;
+        String label;
+    }
+    
     private PackageListAdapter mAdapter;
-    private List<PackageInfo> mPackageInfoList = null;
+    private List<MyPackageInfo> mPackageInfoList = new ArrayList<MyPackageInfo>();
     private Handler mHandler;
-
-    public class PackageListAdapter extends ArrayAdapter<PackageInfo>
-    {
-
-        public PackageListAdapter(Context context)
-        {
-            super(context, android.R.layout.simple_list_item_1);
-            mPackageInfoList = context.getPackageManager().getInstalledPackages(0);
+    private BroadcastReceiver mRegisteredReceiver;
+
+    public class PackageListAdapter extends ArrayAdapter<MyPackageInfo> {
+
+        public PackageListAdapter(Context context) {
+            super(context, R.layout.package_list_item);
+            List<PackageInfo> pkgs = context.getPackageManager().getInstalledPackages(0);
+            for (int i=0; i<pkgs.size(); i++) {
+                MyPackageInfo info = new MyPackageInfo();
+                info.info = pkgs.get(i);
+                info.label = info.info.applicationInfo.loadLabel(getPackageManager()).toString();
+                mPackageInfoList.add(info);
+            }
             if (mPackageInfoList != null) {
                 Collections.sort(mPackageInfoList, sDisplayNameComparator);
             }
@@ -59,10 +70,13 @@ public class PackageBrowser extends ListActivity
         }
     
         @Override
-        public void bindView(View view, PackageInfo info)
-        {
-            TextView text = (TextView)view.findViewById(android.R.id.text1);
-            text.setText(info.packageName);
+        public void bindView(View view, MyPackageInfo info) {
+            ImageView icon = (ImageView)view.findViewById(R.id.icon);
+            TextView name = (TextView)view.findViewById(R.id.name);
+            TextView description = (TextView)view.findViewById(R.id.description);
+            icon.setImageDrawable(info.info.applicationInfo.loadIcon(getPackageManager()));
+            name.setText(info.label);
+            description.setText(info.info.packageName);
         }
     }
 
@@ -78,13 +92,11 @@ public class PackageBrowser extends ListActivity
         }
     }
 
-    private final static Comparator sDisplayNameComparator = new Comparator() {
+    private final static Comparator<MyPackageInfo> sDisplayNameComparator
+            = new Comparator<MyPackageInfo>() {
         public final int
-        compare(Object a, Object b)
-        {
-            CharSequence  sa = ((PackageInfo) a).packageName;
-            CharSequence  sb = ((PackageInfo) b).packageName;
-            return collator.compare(sa, sb);
+        compare(MyPackageInfo a, MyPackageInfo b) {
+            return collator.compare(a.label, b.label);
         }
 
         private final Collator   collator = Collator.getInstance();
@@ -98,6 +110,14 @@ public class PackageBrowser extends ListActivity
         registerIntentReceivers();
     }
 
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (mRegisteredReceiver != null) {
+            unregisterReceiver(mRegisteredReceiver);
+        }
+    }
+
     private void setupAdapter() {
         mAdapter = new PackageListAdapter(this);
         setListAdapter(mAdapter);
@@ -119,9 +139,9 @@ public class PackageBrowser extends ListActivity
         final int curSelection = getSelectedItemPosition();
         if (curSelection >= 0) {
             // todo: verification dialog for package deletion
-            final PackageInfo packageInfo = mAdapter.itemForPosition(curSelection);
+            final MyPackageInfo packageInfo = mAdapter.itemForPosition(curSelection);
             if (packageInfo != null) {
-                getPackageManager().deletePackage(packageInfo.packageName,
+                getPackageManager().deletePackage(packageInfo.info.packageName,
                                                   new IPackageDeleteObserver.Stub() {
                     public void packageDeleted(boolean succeeded) throws RemoteException {
                         if (succeeded) {
@@ -133,7 +153,7 @@ public class PackageBrowser extends ListActivity
                                 });
 
                             // todo: verification dialog for data directory
-                            final String dataPath = packageInfo.applicationInfo.dataDir;
+                            final String dataPath = packageInfo.info.applicationInfo.dataDir;
                             // todo: delete the data directory
                         } else {
                             mHandler.post(new Runnable() {
@@ -159,17 +179,17 @@ public class PackageBrowser extends ListActivity
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addDataScheme("package");
-        registerReceiver(new ApplicationsIntentReceiver(), filter);
+        mRegisteredReceiver = new ApplicationsIntentReceiver();
+        registerReceiver(mRegisteredReceiver, filter);
     }
 
     @Override
-    protected void onListItemClick(ListView l, View v, int position, long id)
-    {
-        PackageInfo info =
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        MyPackageInfo info =
             mAdapter.itemForPosition(position);
         if (info != null) {
             Intent intent = new Intent(
-                null, Uri.fromParts("package", info.packageName, null));
+                null, Uri.fromParts("package", info.info.packageName, null));
             intent.setClass(this, PackageSummary.class);
             startActivity(intent);
         }
index a6bbbb2..5610559 100644 (file)
@@ -31,6 +31,7 @@ import android.content.pm.ServiceInfo;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.Button;
@@ -90,7 +91,8 @@ public class PackageSummary extends Activity {
             info = pm.getPackageInfo(mPackageName,
                 PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
                 | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS
-                | PackageManager.GET_INSTRUMENTATION);
+                | PackageManager.GET_INSTRUMENTATION
+                | PackageManager.GET_DISABLED_COMPONENTS);
         } catch (PackageManager.NameNotFoundException e) {
         }
 
@@ -192,6 +194,7 @@ public class PackageSummary extends Activity {
                     ActivityInfo ai = info.receivers[i];
                     Button view = (Button)inflate.inflate(
                         R.layout.package_item, null, false);
+                    Log.i("foo", "Receiver #" + i + " of " + N + ": " + ai);
                     setItemText(view, info, ai.name);
                     receivers.addView(view, lp);
                 }
index fc157fd..20542a2 100644 (file)
@@ -51,9 +51,6 @@ obj/framework.aidl platforms/${PLATFORM_NAME}/framework.aidl
 # sdk scripts
 development/tools/scripts/AndroidManifest.template platforms/${PLATFORM_NAME}/templates/AndroidManifest.template
 development/tools/scripts/AndroidManifest.tests.template platforms/${PLATFORM_NAME}/templates/AndroidManifest.tests.template
-development/tools/scripts/iml.template platforms/${PLATFORM_NAME}/templates/iml.template
-development/tools/scripts/ipr.template platforms/${PLATFORM_NAME}/templates/ipr.template
-development/tools/scripts/iws.template platforms/${PLATFORM_NAME}/templates/iws.template
 development/tools/scripts/java_file.template platforms/${PLATFORM_NAME}/templates/java_file.template
 development/tools/scripts/java_tests_file.template platforms/${PLATFORM_NAME}/templates/java_tests_file.template
 development/tools/scripts/layout.template platforms/${PLATFORM_NAME}/templates/layout.template
index 4c10c07..f5ca8b4 100644 (file)
@@ -74,7 +74,7 @@ TARGET_AR      := $(TOOLCHAIN_PREFIX)ar
 TARGET_ARFLAGS := crs
 
 TARGET_LIBGCC := $(shell $(TARGET_CC) -mthumb-interwork -print-libgcc-file-name)
-TARGET_LDLIBS := -Wl,-rpath-link=$(SYSROOT)/usr/lib $(TARGET_LIBGCC)
+TARGET_LDLIBS := -Wl,-rpath-link=$(SYSROOT)/usr/lib
 
 # These flags are used to ensure that a binary doesn't reference undefined
 # flags.
@@ -84,6 +84,15 @@ TARGET_NO_UNDEFINED_LDFLAGS := -Wl,--no-undefined
 # this toolchain's generated binaries
 TARGET_ABI_SUBDIR := armeabi
 
+# NOTE: Ensure that TARGET_LIBGCC is placed after all private objects
+#       and static libraries, but before any other library in the link
+#       command line when generating shared libraries and executables.
+#
+#       This ensures that all libgcc.a functions required by the target
+#       will be included into it, instead of relying on what's available
+#       on other libraries like libc.so, which may change between system
+#       releases due to toolchain or library changes.
+#
 define cmd-build-shared-library
 $(TARGET_CC) \
     -nostdlib -Wl,-soname,$(notdir $@) \
@@ -93,6 +102,7 @@ $(TARGET_CC) \
     $(PRIVATE_WHOLE_STATIC_LIBRARIES) \
     -Wl,--no-whole-archive \
     $(PRIVATE_STATIC_LIBRARIES) \
+    $(TARGET_LIBGCC) \
     $(PRIVATE_SHARED_LIBRARIES) \
     $(PRIVATE_LDFLAGS) \
     $(PRIVATE_LDLIBS) \
@@ -105,10 +115,11 @@ $(TARGET_CC) \
     -Wl,-dynamic-linker,/system/bin/linker \
     -Wl,--gc-sections \
     -Wl,-z,nocopyreloc \
-    $(PRIVATE_SHARED_LIBRARIES) \
     $(TARGET_CRTBEGIN_DYNAMIC_O) \
     $(PRIVATE_OBJECTS) \
     $(PRIVATE_STATIC_LIBRARIES) \
+    $(TARGET_LIBGCC) \
+    $(PRIVATE_SHARED_LIBRARIES) \
     $(PRIVATE_LDFLAGS) \
     $(PRIVATE_LDLIBS) \
     $(TARGET_CRTEND_O) \
index faad11d..c03fc60 100644 (file)
@@ -1,6 +1,14 @@
 Android NDK ChangeLog:
 
 -------------------------------------------------------------------------------
+current version
+
+IMPORTANT BUG FIXES:
+
+- Make target shared libraries portable to systems that don't use the exact same
+  toolchain (GCC 4.2.1) .
+
+-------------------------------------------------------------------------------
 android-ndk-1.6_r1
 
 IMPORTANT BUG FIXES:
@@ -24,7 +32,7 @@ IMPORTANT BUG FIXES:
   in $(CLEAR_VARS) script.
 
 
-IMPORTANT CHANGES
+IMPORTANT CHANGES:
 
 - The 'sources' directory is gone. The NDK build system now looks for
   $(APP_PROJECT_PATH)/jni/Android.mk by default. You can override this with
index 21d933c..d62eb32 100755 (executable)
@@ -133,19 +133,22 @@ public class JetBoy extends Activity implements View.OnClickListener {
      */
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent msg) {
-
-        if (keyCode == 4)
-            super.onKeyDown(keyCode, msg);
-
-        return mJetBoyThread.doKeyDown(keyCode, msg);
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            return super.onKeyDown(keyCode, msg);
+        } else {
+            return mJetBoyThread.doKeyDown(keyCode, msg);
+        }
     }
 
     /**
-     * Standard override for key-up. We actually care about these, so we can
-     * turn off the engine or stop rotating.
+     * Standard override for key-up.
      */
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent msg) {
-        return mJetBoyThread.doKeyUp(keyCode, msg);
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            return super.onKeyUp(keyCode, msg);
+        } else {
+            return mJetBoyThread.doKeyUp(keyCode, msg);
+        }
     }
 }
index 6d38d1d..7b75a68 100644 (file)
@@ -366,14 +366,16 @@ See test_defs.xsd for more information.
 <test name="contactsprov"
     build_path="packages/providers/ContactsProvider/tests"
     package="com.android.providers.contacts.tests"
-    coverage_target="ContactsProvider" />
+    coverage_target="ContactsProvider"
+    continuous="true" />
 
 <test name="contacts"
     build_path="packages/apps/Contacts"
     package="com.android.contacts.tests"
     runner="android.test.InstrumentationTestRunner"
     coverage_target="Contacts"
-    description="Tests for the Contacts app." />
+    description="Tests for the Contacts app."
+    continuous="true" />
 
 <test name="gcontactsprov"
     build_path="packages/providers/GoogleContactsProvider/tests"
diff --git a/tools/anttasks/src/com/android/ant/AndroidXPathFactory.java b/tools/anttasks/src/com/android/ant/AndroidXPathFactory.java
deleted file mode 100644 (file)
index 45ccf42..0000000
+++ /dev/null
@@ -1,89 +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.ant;
-
-import com.android.sdklib.SdkConstants;
-
-import java.util.Iterator;
-
-import javax.xml.XMLConstants;
-import javax.xml.namespace.NamespaceContext;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathFactory;
-
-/**
- * XPath factory with automatic support for the android namespace.
- */
-class AndroidXPathFactory {
-    public final static String DEFAULT_NS_PREFIX = "android"; //$NON-NLS-1$
-
-    private final static XPathFactory sFactory = XPathFactory.newInstance();
-
-    /** Namespace context for Android resource XML files. */
-    private static class AndroidNamespaceContext implements NamespaceContext {
-        private String mAndroidPrefix;
-
-        /**
-         * Construct the context with the prefix associated with the android namespace.
-         * @param androidPrefix the Prefix
-         */
-        public AndroidNamespaceContext(String androidPrefix) {
-            mAndroidPrefix = androidPrefix;
-        }
-
-        public String getNamespaceURI(String prefix) {
-            if (prefix != null) {
-                if (prefix.equals(mAndroidPrefix)) {
-                    return SdkConstants.NS_RESOURCES;
-                }
-            }
-
-            return XMLConstants.NULL_NS_URI;
-        }
-
-        public String getPrefix(String namespaceURI) {
-            // This isn't necessary for our use.
-            assert false;
-            return null;
-        }
-
-        public Iterator<?> getPrefixes(String namespaceURI) {
-            // This isn't necessary for our use.
-            assert false;
-            return null;
-        }
-    }
-
-    /**
-     * Creates a new XPath object, specifying which prefix in the query is used for the
-     * android namespace.
-     * @param androidPrefix The namespace prefix.
-     */
-    public static XPath newXPath(String androidPrefix) {
-        XPath xpath = sFactory.newXPath();
-        xpath.setNamespaceContext(new AndroidNamespaceContext(androidPrefix));
-        return xpath;
-    }
-
-    /**
-     * Creates a new XPath object using the default prefix for the android namespace.
-     * @see #DEFAULT_NS_PREFIX
-     */
-    public static XPath newXPath() {
-        return newXPath(DEFAULT_NS_PREFIX);
-    }
-}
index 1201108..f13cccd 100644 (file)
@@ -23,7 +23,7 @@ import com.android.sdklib.SdkManager;
 import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
 import com.android.sdklib.internal.project.ProjectProperties;
 import com.android.sdklib.xml.AndroidXPathFactory;
-import com.android.sdklib.xml.ManifestConstants;
+import com.android.sdklib.xml.AndroidManifest;
 
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Project;
@@ -264,10 +264,11 @@ public final class SetupTask extends ImportTask {
 
             XPath xPath = AndroidXPathFactory.newXPath();
 
-            String value = xPath.evaluate("/" + ManifestConstants.NODE_MANIFEST +"/" +
-                    ManifestConstants.NODE_USES_SDK + "/@" +
-                    AndroidXPathFactory.DEFAULT_NS_PREFIX + ":" +
-                    ManifestConstants.ATTRIBUTE_MIN_SDK_VERSION,
+            String value = xPath.evaluate(
+                    "/"  + AndroidManifest.NODE_MANIFEST +
+                    "/"  + AndroidManifest.NODE_USES_SDK +
+                    "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + ":" +
+                            AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION,
                     new InputSource(new FileInputStream(manifest)));
 
             if (androidVersion.isPreview()) {
@@ -290,19 +291,19 @@ public final class SetupTask extends ImportTask {
                     // looks like it's not a number: error!
                     throw new BuildException(String.format(
                             "Attribute %1$s in AndroidManifest.xml must be an Integer!",
-                            ManifestConstants.ATTRIBUTE_MIN_SDK_VERSION));
+                            AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION));
                 }
 
                 int projectApiLevel = androidVersion.getApiLevel();
                 if (minSdkValue < projectApiLevel) {
                     System.out.println(String.format(
                             "WARNING: Attribute %1$s in AndroidManifest.xml (%2$d) is lower than the project target API level (%3$d)",
-                            ManifestConstants.ATTRIBUTE_MIN_SDK_VERSION,
+                            AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION,
                             minSdkValue, projectApiLevel));
                 } else if (minSdkValue > androidVersion.getApiLevel()) {
                     System.out.println(String.format(
                             "WARNING: Attribute %1$s in AndroidManifest.xml (%2$d) is higher than the project target API level (%3$d)",
-                            ManifestConstants.ATTRIBUTE_MIN_SDK_VERSION,
+                            AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION,
                             minSdkValue, projectApiLevel));
                 }
             } else {
index 73cf86a..b9cfb71 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.ant;
 
+import com.android.sdklib.xml.AndroidXPathFactory;
+
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Task;
 import org.apache.tools.ant.types.Path;
index f17b3c8..047c985 100644 (file)
@@ -1026,10 +1026,16 @@ public class AdtPlugin extends AbstractUIPlugin {
 
                         progress.setTaskName(Messages.AdtPlugin_Parsing_Resources);
 
-                        int n = sdk.getTargets().length;
+                        final IAndroidTarget[] targets = sdk.getTargets();
+                        final int n = targets.length;
                         if (n > 0) {
+                            // load the layout devices.
+                            sdk.parseAddOnLayoutDevices();
+
+                            // load the rest of the targes.
+                            // TODO: make this on-demand.
                             int w = 60 / n;
-                            for (IAndroidTarget target : sdk.getTargets()) {
+                            for (IAndroidTarget target : targets) {
                                 SubMonitor p2 = progress.newChild(w);
                                 IStatus status = new AndroidTargetParser(target).run(p2);
                                 if (status.getCode() != IStatus.OK) {
index af0960c..5b6293c 100644 (file)
@@ -27,7 +27,7 @@ import com.android.ide.eclipse.adt.internal.sdk.Sdk;
 import com.android.sdklib.AndroidVersion;
 import com.android.sdklib.IAndroidTarget;
 import com.android.sdklib.SdkConstants;
-import com.android.sdklib.xml.ManifestConstants;
+import com.android.sdklib.xml.AndroidManifest;
 
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
@@ -336,7 +336,7 @@ public class PreCompilerBuilder extends BaseBuilder {
                         // integer minSdk when the target is a preview => fatal error
                         String msg = String.format(
                                 "Platform %1$s is a preview and requires appication manifest to set %2$s to '%1$s'",
-                                codename, ManifestConstants.ATTRIBUTE_MIN_SDK_VERSION);
+                                codename, AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION);
                         AdtPlugin.printErrorToConsole(project, msg);
                         BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
                                 IMarker.SEVERITY_ERROR);
@@ -345,7 +345,7 @@ public class PreCompilerBuilder extends BaseBuilder {
                         // integer minSdk is not high enough for the target => warning
                         String msg = String.format(
                                 "Attribute %1$s (%2$d) is lower than the project target API level (%3$d)",
-                                ManifestConstants.ATTRIBUTE_MIN_SDK_VERSION,
+                                AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION,
                                 minSdkValue, projectVersion.getApiLevel());
                         AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
                         BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
@@ -354,7 +354,7 @@ public class PreCompilerBuilder extends BaseBuilder {
                         // integer minSdk is too high for the target => warning
                         String msg = String.format(
                                 "Attribute %1$s (%2$d) is higher than the project target API level (%3$d)",
-                                ManifestConstants.ATTRIBUTE_MIN_SDK_VERSION,
+                                AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION,
                                 minSdkValue, projectVersion.getApiLevel());
                         AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
                         BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
@@ -368,7 +368,7 @@ public class PreCompilerBuilder extends BaseBuilder {
                         // platform is not a preview => fatal error
                         String msg = String.format(
                                 "Manifest attribute '%1$s' is set to '%2$s'. Integer is expected.",
-                                ManifestConstants.ATTRIBUTE_MIN_SDK_VERSION, minSdkVersion);
+                                AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, minSdkVersion);
                         AdtPlugin.printErrorToConsole(project, msg);
                         BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
                                 IMarker.SEVERITY_ERROR);
@@ -377,7 +377,7 @@ public class PreCompilerBuilder extends BaseBuilder {
                         // platform and manifest codenames don't match => fatal error.
                         String msg = String.format(
                                 "Value of manifest attribute '%1$s' does not match platform codename '%2$s'",
-                                ManifestConstants.ATTRIBUTE_MIN_SDK_VERSION, codename);
+                                AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, codename);
                         AdtPlugin.printErrorToConsole(project, msg);
                         BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
                                 IMarker.SEVERITY_ERROR);
@@ -390,7 +390,7 @@ public class PreCompilerBuilder extends BaseBuilder {
                 String codename = projectTarget.getVersion().getCodename();
                 String msg = String.format(
                         "Platform %1$s is a preview and requires appication manifests to set %2$s to '%1$s'",
-                        codename, ManifestConstants.ATTRIBUTE_MIN_SDK_VERSION);
+                        codename, AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION);
                 AdtPlugin.printErrorToConsole(project, msg);
                 BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
                         IMarker.SEVERITY_ERROR);
index cab6829..ef0db5a 100755 (executable)
@@ -679,6 +679,8 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE
         // enable the create button if the current and edited config are not equals\r
         mConfigComposite.setEnabledCreate(\r
                 mEditedConfig.equals(mConfigComposite.getCurrentConfig()) == false);\r
+\r
+        reloadConfigurationUi(false /*notifyListener*/);\r
     }\r
 \r
     public Clipboard getClipboard() {\r
@@ -967,7 +969,7 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE
         }\r
     }\r
 \r
-    public void reloadConfigurationUi() {\r
+    public void reloadConfigurationUi(boolean notifyListener) {\r
         // enable the clipping button if it's supported.\r
         Sdk currentSdk = Sdk.getCurrent();\r
         if (currentSdk != null) {\r
@@ -975,6 +977,7 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE
             AndroidTargetData data = currentSdk.getTargetData(target);\r
             if (data != null) {\r
                 LayoutBridge bridge = data.getLayoutBridge();\r
+                mConfigComposite.reloadDevices(notifyListener);\r
                 mConfigComposite.setClippingSupport(bridge.apiLevel >= 4);\r
             }\r
         }\r
index 1c9cac3..f3fd97a 100644 (file)
@@ -548,7 +548,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
         mConfigComposite.setEnabledCreate(
                 mEditedConfig.equals(mConfigComposite.getCurrentConfig()) == false);
 
-        reloadConfigurationUi();
+        reloadConfigurationUi(false /*notifyListener*/);
     }
 
     public Rectangle getBounds() {
@@ -730,7 +730,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
         PaletteFactory.createPaletteRoot(mPaletteRoot, mLayoutEditor.getTargetData());
     }
 
-    public void reloadConfigurationUi() {
+    public void reloadConfigurationUi(boolean notifyListener) {
         // enable the clipping button if it's supported.
         Sdk currentSdk = Sdk.getCurrent();
         if (currentSdk != null) {
@@ -738,6 +738,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
             AndroidTargetData data = currentSdk.getTargetData(target);
             if (data != null) {
                 LayoutBridge bridge = data.getLayoutBridge();
+                mConfigComposite.reloadDevices(notifyListener);
                 mConfigComposite.setClippingSupport(bridge.apiLevel >= 4);
             }
         }
index ca11fc7..99670d8 100644 (file)
@@ -410,7 +410,7 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa
         if (mGraphicalEditor != null) {
             mGraphicalEditor.reloadEditor();
             mGraphicalEditor.reloadPalette();
-            mGraphicalEditor.reloadConfigurationUi();
+            mGraphicalEditor.reloadConfigurationUi(true /*notify listener */);
             mGraphicalEditor.recomputeLayout();
         }
     }
index fe98ee8..969050a 100644 (file)
@@ -28,6 +28,7 @@ import com.android.ide.eclipse.adt.internal.resources.configurations.VersionQual
 import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier.ScreenOrientation;
 import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
 import com.android.ide.eclipse.adt.internal.sdk.DeviceConfiguration;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
 import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.LanguageRegionVerifier;
 import com.android.layoutlib.api.IResourceValue;
 import com.android.layoutlib.api.IStyleResourceValue;
@@ -46,6 +47,7 @@ import org.eclipse.swt.widgets.Label;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedSet;
@@ -73,7 +75,7 @@ public class ConfigurationComposite extends Composite {
     /** The {@link FolderConfiguration} representing the state of the UI controls */
     private final FolderConfiguration mCurrentConfig = new FolderConfiguration();
 
-    private DeviceConfiguration[] mDevices;
+    private List<DeviceConfiguration> mDevices;
 
     private final ArrayList<ResourceQualifier[] > mLocaleList =
         new ArrayList<ResourceQualifier[]>();
@@ -103,7 +105,9 @@ public class ConfigurationComposite extends Composite {
     public ConfigurationComposite(IConfigListener listener, Composite parent, int style) {
         super(parent, style);
         mListener = listener;
-        mDevices = DeviceConfiguration.getDevices();
+        if (Sdk.getCurrent() != null) {
+            mDevices = Sdk.getCurrent().getLayoutDevices();
+        }
 
         GridLayout gl;
         GridData gd;
@@ -141,32 +145,17 @@ public class ConfigurationComposite extends Composite {
 
         new Label(this, SWT.NONE).setText("Devices");
         mDeviceList = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
-        // fill with the devices
-        for (DeviceConfiguration device : mDevices) {
-            mDeviceList.add(device.getName());
-        }
-
-        mDeviceList.select(0);
         mDeviceList.setLayoutData(new GridData(
                 GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
         mDeviceList.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
-                onDeviceChange();
+                onDeviceChange(true /* recomputeLayout*/);
             }
         });
 
         new Label(this, SWT.NONE).setText("Config");
         mDeviceConfigs = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
-        Map<String, FolderConfiguration> configs = mDevices[0].getConfigs();
-        Set<String> configNames = configs.keySet();
-        for (String name : configNames) {
-            mDeviceConfigs.add(name);
-        }
-        mDeviceConfigs.select(0);
-        if (configNames.size() == 1) {
-            mDeviceConfigs.setEnabled(false);
-        }
         mDeviceConfigs.setLayoutData(new GridData(
                 GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
         mDeviceConfigs.addSelectionListener(new SelectionAdapter() {
@@ -224,9 +213,12 @@ public class ConfigurationComposite extends Composite {
             }
         });
 
+        initUiWithDevices();
+
         onDeviceConfigChange();
     }
 
+
     public FolderConfiguration getCurrentConfig() {
         return mCurrentConfig;
     }
@@ -458,6 +450,45 @@ public class ConfigurationComposite extends Composite {
     }
 
     /**
+     * Reloads the list of {@link DeviceConfiguration} from the {@link Sdk}.
+     * @param notifyListener
+     */
+    public void reloadDevices(boolean notifyListener) {
+        mDevices = Sdk.getCurrent().getLayoutDevices();
+        initUiWithDevices();
+        onDeviceChange(notifyListener);
+    }
+
+    /**
+     * Init the UI with the list of Devices.
+     */
+    private void initUiWithDevices() {
+        // remove older devices if applicable
+        mDeviceList.removeAll();
+        mDeviceConfigs.removeAll();
+
+        // fill with the devices
+        if (mDevices != null) {
+            for (DeviceConfiguration device : mDevices) {
+                mDeviceList.add(device.getName());
+            }
+            mDeviceList.select(0);
+
+            if (mDevices.size() > 0) {
+                Map<String, FolderConfiguration> configs = mDevices.get(0).getConfigs();
+                Set<String> configNames = configs.keySet();
+                for (String name : configNames) {
+                    mDeviceConfigs.add(name);
+                }
+                mDeviceConfigs.select(0);
+                if (configNames.size() == 1) {
+                    mDeviceConfigs.setEnabled(false);
+                }
+            }
+        }
+    }
+
+    /**
      * Call back for language combo selection
      */
     private void onLocaleChange() {
@@ -478,10 +509,10 @@ public class ConfigurationComposite extends Composite {
         }
     }
 
-    private void onDeviceChange() {
+    private void onDeviceChange(boolean recomputeLayout) {
 
         int deviceIndex = mDeviceList.getSelectionIndex();
-        DeviceConfiguration device = mDevices[deviceIndex];
+        DeviceConfiguration device = mDevices.get(deviceIndex);
 
         mDeviceConfigs.removeAll();
 
@@ -495,32 +526,36 @@ public class ConfigurationComposite extends Composite {
             mDeviceConfigs.setEnabled(false);
         }
 
-        onDeviceConfigChange();
+        if (recomputeLayout) {
+            onDeviceConfigChange();
+        }
     }
 
     private void onDeviceConfigChange() {
-        int deviceIndex = mDeviceList.getSelectionIndex();
-        DeviceConfiguration device = mDevices[deviceIndex];
+        if (mDevices != null) {
+            int deviceIndex = mDeviceList.getSelectionIndex();
+            DeviceConfiguration device = mDevices.get(deviceIndex);
 
-        int configIndex = mDeviceConfigs.getSelectionIndex();
-        String name = mDeviceConfigs.getItem(configIndex);
-        FolderConfiguration config = device.getConfigs().get(name);
+            int configIndex = mDeviceConfigs.getSelectionIndex();
+            String name = mDeviceConfigs.getItem(configIndex);
+            FolderConfiguration config = device.getConfigs().get(name);
 
-        // get the current qualifiers from the current config
-        LanguageQualifier lang = mCurrentConfig.getLanguageQualifier();
-        RegionQualifier region = mCurrentConfig.getRegionQualifier();
-        VersionQualifier version = mCurrentConfig.getVersionQualifier();
+            // get the current qualifiers from the current config
+            LanguageQualifier lang = mCurrentConfig.getLanguageQualifier();
+            RegionQualifier region = mCurrentConfig.getRegionQualifier();
+            VersionQualifier version = mCurrentConfig.getVersionQualifier();
 
-        // replace the config with the one from the device
-        mCurrentConfig.set(config);
+            // replace the config with the one from the device
+            mCurrentConfig.set(config);
 
-        // and put back the rest of the qualifiers
-        mCurrentConfig.addQualifier(lang);
-        mCurrentConfig.addQualifier(region);
-        mCurrentConfig.addQualifier(version);
+            // and put back the rest of the qualifiers
+            mCurrentConfig.addQualifier(lang);
+            mCurrentConfig.addQualifier(region);
+            mCurrentConfig.addQualifier(version);
 
-        if (mListener != null) {
-            mListener.onConfigurationChange();
+            if (mListener != null) {
+                mListener.onConfigurationChange();
+            }
         }
     }
 
@@ -603,3 +638,4 @@ public class ConfigurationComposite extends Composite {
         return false;
     }
 }
+
index 3119b70..d5abc09 100644 (file)
@@ -25,8 +25,8 @@ import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.Android
 import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper;
 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiTextAttributeNode;
-import com.android.ide.eclipse.adt.internal.project.AndroidManifestParser;
 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
+import com.android.sdklib.xml.AndroidManifest;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
@@ -94,9 +94,9 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
     private IPostTypeCreationAction mPostCreationAction;
     private boolean mMandatory;
     private final boolean mDefaultToProjectOnly;
-    
+
     private class HierarchyTypeSelection extends TypeSelectionExtension {
-        
+
         private IJavaProject mJavaProject;
         private IType mReferenceType;
         private Button mProjectOnly;
@@ -112,13 +112,13 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
         public ITypeInfoFilterExtension getFilterExtension() {
             return new ITypeInfoFilterExtension() {
                 public boolean select(ITypeInfoRequestor typeInfoRequestor) {
-                    
+
                     boolean projectOnly = mUseProjectOnly;
-                    
+
                     String packageName = typeInfoRequestor.getPackageName();
                     String typeName = typeInfoRequestor.getTypeName();
                     String enclosingType = typeInfoRequestor.getEnclosingName();
-                    
+
                     // build the full class name.
                     StringBuilder sb = new StringBuilder(packageName);
                     sb.append('.');
@@ -127,9 +127,9 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
                         sb.append('.');
                     }
                     sb.append(typeName);
-                    
+
                     String className = sb.toString();
-                    
+
                     try {
                         IType type = mJavaProject.findType(className);
 
@@ -150,11 +150,11 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
                                 return false;
                             }
                         }
-                        
+
                         // get the type hierarchy and reference type is one of the super classes.
                         ITypeHierarchy hierarchy = type.newSupertypeHierarchy(
                                 new NullProgressMonitor());
-                        
+
                         IType[] supertypes = hierarchy.getAllSupertypes(type);
                         int n = supertypes.length;
                         for (int i = 0; i < n; i++) {
@@ -165,12 +165,12 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
                         }
                     } catch (JavaModelException e) {
                     }
-                    
+
                     return false;
                 }
             };
         }
-        
+
         @Override
         public Control createContentArea(Composite parent) {
 
@@ -178,10 +178,10 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
             mProjectOnly.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
             mProjectOnly.setText(String.format("Display classes from sources of project '%s' only",
                     mJavaProject.getProject().getName()));
-            
+
             mUseProjectOnly = mDefaultToProjectOnly;
             mProjectOnly.setSelection(mUseProjectOnly);
-            
+
             mProjectOnly.addSelectionListener(new SelectionAdapter() {
                 @Override
                 public void widgetSelected(SelectionEvent e) {
@@ -190,7 +190,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
                     getTypeSelectionComponent().triggerSearch();
                 }
             });
-            
+
             return super.createContentArea(parent);
         }
     }
@@ -216,13 +216,13 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
      * @param mandatory indicates if the class value is mandatory
      * @param attributeDescriptor the {@link AttributeDescriptor} object linked to the Ui Node.
      * @param defaultToProjectOnly When true display classes of this project only by default.
-     *         When false any class path will be considered. The user can always toggle this. 
+     *         When false any class path will be considered. The user can always toggle this.
      */
     public UiClassAttributeNode(String referenceClass, IPostTypeCreationAction postCreationAction,
             boolean mandatory, AttributeDescriptor attributeDescriptor, UiElementNode uiParent,
             boolean defaultToProjectOnly) {
         super(attributeDescriptor, uiParent);
-        
+
         mReferenceClass = referenceClass;
         mPostCreationAction = postCreationAction;
         mMandatory = mandatory;
@@ -256,7 +256,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
         });
         formText.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
         SectionHelper.addControlTooltip(formText, desc.getTooltip());
-        
+
         Composite composite = toolkit.createComposite(parent);
         composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE));
         GridLayout gl = new GridLayout(2, false);
@@ -265,13 +265,13 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
         // Fixes missing text borders under GTK... also requires adding a 1-pixel margin
         // for the text field below
         toolkit.paintBordersFor(composite);
-        
+
         final Text text = toolkit.createText(composite, getCurrentValue());
         GridData gd = new GridData(GridData.FILL_HORIZONTAL);
         gd.horizontalIndent = 1;  // Needed by the fixed composite borders under GTK
         text.setLayoutData(gd);
         Button browseButton = toolkit.createButton(composite, "Browse...", SWT.PUSH);
-        
+
         setTextWidget(text);
 
         browseButton.addSelectionListener(new SelectionAdapter() {
@@ -282,9 +282,9 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
             }
         });
     }
-    
+
     /* (non-java doc)
-     * 
+     *
      * Add a modify listener that will check the validity of the class
      */
     @Override
@@ -305,12 +305,12 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
                     String javaPackage = getManifestPackage();
 
                     // build the fully qualified name of the class
-                    String className = AndroidManifestParser.combinePackageAndClassName(
+                    String className = AndroidManifest.combinePackageAndClassName(
                             javaPackage, textValue);
-                    
+
                     // only test the vilibility for activities.
                     boolean testVisibility = AndroidConstants.CLASS_ACTIVITY.equals(
-                            mReferenceClass); 
+                            mReferenceClass);
 
                     // test the class
                     setErrorMessage(BaseProjectHelper.testClassForManifest(
@@ -339,11 +339,11 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
 
     private void handleBrowseClick() {
         Text text = getTextWidget();
-        
+
         // we need to get the project of the manifest.
         IProject project = getProject();
         if (project != null) {
-            
+
             // Create a search scope including only the source folder of the current
             // project.
             IPackageFragmentRoot[] packageFragmentRoots = getPackageFragmentRoots(project,
@@ -365,7 +365,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
                 if (dlg instanceof ITypeSelectionComponent) {
                     ((ITypeSelectionComponent)dlg).triggerSearch();
                 }
-                
+
                 if (dlg.open() == Window.OK) {
                     Object[] results = dlg.getResult();
                     if (results.length == 1) {
@@ -384,7 +384,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
 
         // get the package name from the manifest.
         String packageName = getManifestPackage();
-        
+
         if (className.length() == 0) {
             createNewClass(packageName, null /* className */);
         } else {
@@ -398,10 +398,10 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
                     fullClassName = packageName + "." + className; //$NON-NLS-1$
                 }
             }
-            
+
             // in case the type is enclosed, we need to replace the $ with .
             fullClassName = fullClassName.replaceAll("\\$", "\\."); //$NON-NLS-1$ //$NON-NLS2$
-            
+
             // now we try to find the file that contains this class and we open it in the editor.
             IProject project = getProject();
             IJavaProject javaProject = JavaCore.create(project);
@@ -427,7 +427,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
             }
         }
     }
-    
+
     private IProject getProject() {
         UiElementNode uiNode = getUiParent();
         AndroidEditor editor = uiNode.getEditor();
@@ -437,7 +437,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
             IFile file = ((IFileEditorInput)input).getFile();
             return file.getProject();
         }
-        
+
         return null;
     }
 
@@ -449,7 +449,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
     private String getManifestPackage() {
         // get the root uiNode to get the 'package' attribute value.
         UiElementNode rootNode = getUiParent().getUiRoot();
-                  
+
         Element xmlElement = (Element) rootNode.getXmlNode();
 
         if (xmlElement != null) {
@@ -485,20 +485,20 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
 
         return result.toArray(new IPackageFragmentRoot[result.size()]);
     }
-    
+
     private void handleNewType(IType type) {
         Text text = getTextWidget();
 
         // get the fully qualified name with $ to properly detect the enclosing types.
         String name = type.getFullyQualifiedName('$');
-        
+
         String packageValue = getManifestPackage();
-        
+
         // check if the class doesn't start with the package.
         if (packageValue.length() > 0 && name.startsWith(packageValue)) {
             // if it does, we remove the package and the first dot.
             name = name.substring(packageValue.length() + 1);
-            
+
             // look for how many segments we have left.
             // if one, just write it that way.
             // if more than one, write it with a leading dot.
@@ -512,14 +512,14 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
             text.setText(name);
         }
     }
-    
+
     private void createNewClass(String packageName, String className) {
         // create the wizard page for the class creation, and configure it
         NewClassWizardPage page = new NewClassWizardPage();
-        
+
         // set the parent class
         page.setSuperClass(mReferenceClass, true /* canBeModified */);
-        
+
         // get the source folders as java elements.
         IPackageFragmentRoot[] roots = getPackageFragmentRoots(getProject(),
                 true /*include_containers*/);
@@ -527,7 +527,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
         IPackageFragmentRoot currentRoot = null;
         IPackageFragment currentFragment = null;
         int packageMatchCount = -1;
-        
+
         for (IPackageFragmentRoot root : roots) {
             // Get the java element for the package.
             // This method is said to always return a IPackageFragment even if the
@@ -564,7 +564,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
                 }
             }
         }
-        
+
         ArrayList<IPackageFragment> createdFragments = null;
 
         if (currentRoot != null) {
@@ -578,7 +578,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
                 // know what to delete in case of a cancel.
                 try {
                     createdFragments = new ArrayList<IPackageFragment>();
-                    
+
                     int totalCount = packageName.split("\\.").length; //$NON-NLS-1$
                     int count = 0;
                     int index = -1;
@@ -587,7 +587,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
                         index = packageName.indexOf('.', index+1);
                         count++;
                     }
-                    
+
                     // create the rest of the segments, except for the last one as indexOf will
                     // return -1;
                     while (count < totalCount - 1) {
@@ -597,11 +597,11 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
                                 packageName.substring(0, index),
                                 true /* force*/, new NullProgressMonitor()));
                     }
-                    
+
                     // create the last package
                     createdFragments.add(currentRoot.createPackageFragment(
                             packageName, true /* force*/, new NullProgressMonitor()));
-                    
+
                     // set the root and fragment in the Wizard page
                     page.setPackageFragmentRoot(currentRoot, true /* canBeModified*/);
                     page.setPackageFragment(createdFragments.get(createdFragments.size()-1),
@@ -626,27 +626,27 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
             // if we haven't found a valid fragment, we set the root to the first source folder.
             page.setPackageFragmentRoot(roots[0], true /* canBeModified*/);
         }
-        
+
         // if we have a starting class name we use it
         if (className != null) {
             page.setTypeName(className, true /* canBeModified*/);
         }
-        
+
         // create the action that will open it the wizard.
         OpenNewClassWizardAction action = new OpenNewClassWizardAction();
         action.setConfiguredWizardPage(page);
         action.run();
         IJavaElement element = action.getCreatedElement();
-        
+
         if (element != null) {
             if (element.getElementType() == IJavaElement.TYPE) {
-                    
+
                 IType type = (IType)element;
-                
+
                 if (mPostCreationAction != null) {
                     mPostCreationAction.processNewType(type);
                 }
-                
+
                 handleNewType(type);
             }
         } else {
@@ -663,7 +663,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
             }
         }
     }
-    
+
     /**
      * Sets the error messages. If message is <code>null</code>, the message is removed.
      * @param message the message to set, or <code>null</code> to remove the current message
@@ -679,7 +679,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
             getManagedForm().getMessageManager().removeMessage(textWidget, textWidget);
         }
     }
-    
+
     @Override
     public String[] getPossibleValues(String prefix) {
         // TODO: compute a list of existing classes for content assist completion
index 10e727c..f03749c 100644 (file)
@@ -20,7 +20,7 @@ import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.adt.AndroidConstants;
 import com.android.ide.eclipse.adt.internal.project.XmlErrorHandler.XmlErrorListener;
 import com.android.sdklib.SdkConstants;
-import com.android.sdklib.xml.ManifestConstants;
+import com.android.sdklib.xml.AndroidManifest;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IMarker;
@@ -285,55 +285,55 @@ public class AndroidManifestParser {
                     String value;
                     switch (mValidLevel) {
                         case LEVEL_MANIFEST:
-                            if (ManifestConstants.NODE_MANIFEST.equals(localName)) {
+                            if (AndroidManifest.NODE_MANIFEST.equals(localName)) {
                                 // lets get the package name.
                                 mPackage = getAttributeValue(attributes,
-                                        ManifestConstants.ATTRIBUTE_PACKAGE,
+                                        AndroidManifest.ATTRIBUTE_PACKAGE,
                                         false /* hasNamespace */);
                                 mValidLevel++;
                             }
                             break;
                         case LEVEL_APPLICATION:
-                            if (ManifestConstants.NODE_APPLICATION.equals(localName)) {
+                            if (AndroidManifest.NODE_APPLICATION.equals(localName)) {
                                 value = getAttributeValue(attributes,
-                                        ManifestConstants.ATTRIBUTE_PROCESS,
+                                        AndroidManifest.ATTRIBUTE_PROCESS,
                                         true /* hasNamespace */);
                                 if (value != null) {
                                     addProcessName(value);
                                 }
 
                                 value = getAttributeValue(attributes,
-                                        ManifestConstants.ATTRIBUTE_DEBUGGABLE,
+                                        AndroidManifest.ATTRIBUTE_DEBUGGABLE,
                                         true /* hasNamespace*/);
                                 if (value != null) {
                                     mDebuggable = Boolean.parseBoolean(value);
                                 }
 
                                 mValidLevel++;
-                            } else if (ManifestConstants.NODE_USES_SDK.equals(localName)) {
+                            } else if (AndroidManifest.NODE_USES_SDK.equals(localName)) {
                                 mApiLevelRequirement = getAttributeValue(attributes,
-                                        ManifestConstants.ATTRIBUTE_MIN_SDK_VERSION,
+                                        AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION,
                                         true /* hasNamespace */);
-                            } else if (ManifestConstants.NODE_INSTRUMENTATION.equals(localName)) {
+                            } else if (AndroidManifest.NODE_INSTRUMENTATION.equals(localName)) {
                                 processInstrumentationNode(attributes);
                             }
                             break;
                         case LEVEL_ACTIVITY:
-                            if (ManifestConstants.NODE_ACTIVITY.equals(localName)) {
+                            if (AndroidManifest.NODE_ACTIVITY.equals(localName)) {
                                 processActivityNode(attributes);
                                 mValidLevel++;
-                            } else if (ManifestConstants.NODE_SERVICE.equals(localName)) {
+                            } else if (AndroidManifest.NODE_SERVICE.equals(localName)) {
                                 processNode(attributes, AndroidConstants.CLASS_SERVICE);
                                 mValidLevel++;
-                            } else if (ManifestConstants.NODE_RECEIVER.equals(localName)) {
+                            } else if (AndroidManifest.NODE_RECEIVER.equals(localName)) {
                                 processNode(attributes, AndroidConstants.CLASS_BROADCASTRECEIVER);
                                 mValidLevel++;
-                            } else if (ManifestConstants.NODE_PROVIDER.equals(localName)) {
+                            } else if (AndroidManifest.NODE_PROVIDER.equals(localName)) {
                                 processNode(attributes, AndroidConstants.CLASS_CONTENTPROVIDER);
                                 mValidLevel++;
-                            } else if (ManifestConstants.NODE_USES_LIBRARY.equals(localName)) {
+                            } else if (AndroidManifest.NODE_USES_LIBRARY.equals(localName)) {
                                 value = getAttributeValue(attributes,
-                                        ManifestConstants.ATTRIBUTE_NAME,
+                                        AndroidManifest.ATTRIBUTE_NAME,
                                         true /* hasNamespace */);
                                 if (value != null) {
                                     mLibraries.add(value);
@@ -343,26 +343,26 @@ public class AndroidManifestParser {
                         case LEVEL_INTENT_FILTER:
                             // only process this level if we are in an activity
                             if (mCurrentActivity != null &&
-                                    ManifestConstants.NODE_INTENT.equals(localName)) {
+                                    AndroidManifest.NODE_INTENT.equals(localName)) {
                                 mCurrentActivity.resetIntentFilter();
                                 mValidLevel++;
                             }
                             break;
                         case LEVEL_CATEGORY:
                             if (mCurrentActivity != null) {
-                                if (ManifestConstants.NODE_ACTION.equals(localName)) {
+                                if (AndroidManifest.NODE_ACTION.equals(localName)) {
                                     // get the name attribute
                                     String action = getAttributeValue(attributes,
-                                            ManifestConstants.ATTRIBUTE_NAME,
+                                            AndroidManifest.ATTRIBUTE_NAME,
                                             true /* hasNamespace */);
                                     if (action != null) {
                                         mCurrentActivity.setHasAction(true);
                                         mCurrentActivity.setHasMainAction(
                                                 ACTION_MAIN.equals(action));
                                     }
-                                } else if (ManifestConstants.NODE_CATEGORY.equals(localName)) {
+                                } else if (AndroidManifest.NODE_CATEGORY.equals(localName)) {
                                     String category = getAttributeValue(attributes,
-                                            ManifestConstants.ATTRIBUTE_NAME,
+                                            AndroidManifest.ATTRIBUTE_NAME,
                                             true /* hasNamespace */);
                                     if (CATEGORY_LAUNCHER.equals(category)) {
                                         mCurrentActivity.setHasLauncherCategory(true);
@@ -462,14 +462,14 @@ public class AndroidManifestParser {
          */
         private void processActivityNode(Attributes attributes) {
             // lets get the activity name, and add it to the list
-            String activityName = getAttributeValue(attributes, ManifestConstants.ATTRIBUTE_NAME,
+            String activityName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_NAME,
                     true /* hasNamespace */);
             if (activityName != null) {
-                activityName = combinePackageAndClassName(mPackage, activityName);
+                activityName = AndroidManifest.combinePackageAndClassName(mPackage, activityName);
 
                 // get the exported flag.
                 String exportedStr = getAttributeValue(attributes,
-                        ManifestConstants.ATTRIBUTE_EXPORTED, true);
+                        AndroidManifest.ATTRIBUTE_EXPORTED, true);
                 boolean exported = exportedStr == null ||
                         exportedStr.toLowerCase().equals("true"); // $NON-NLS-1$
                 mCurrentActivity = new Activity(activityName, exported);
@@ -485,7 +485,7 @@ public class AndroidManifestParser {
                 mCurrentActivity = null;
             }
 
-            String processName = getAttributeValue(attributes, ManifestConstants.ATTRIBUTE_PROCESS,
+            String processName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_PROCESS,
                     true /* hasNamespace */);
             if (processName != null) {
                 addProcessName(processName);
@@ -500,17 +500,17 @@ public class AndroidManifestParser {
          */
         private void processNode(Attributes attributes, String superClassName) {
             // lets get the class name, and check it if required.
-            String serviceName = getAttributeValue(attributes, ManifestConstants.ATTRIBUTE_NAME,
+            String serviceName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_NAME,
                     true /* hasNamespace */);
             if (serviceName != null) {
-                serviceName = combinePackageAndClassName(mPackage, serviceName);
+                serviceName = AndroidManifest.combinePackageAndClassName(mPackage, serviceName);
 
                 if (mMarkErrors) {
                     checkClass(serviceName, superClassName, false /* testVisibility */);
                 }
             }
 
-            String processName = getAttributeValue(attributes, ManifestConstants.ATTRIBUTE_PROCESS,
+            String processName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_PROCESS,
                     true /* hasNamespace */);
             if (processName != null) {
                 addProcessName(processName);
@@ -525,12 +525,13 @@ public class AndroidManifestParser {
         private void processInstrumentationNode(Attributes attributes) {
             // lets get the class name, and check it if required.
             String instrumentationName = getAttributeValue(attributes,
-                    ManifestConstants.ATTRIBUTE_NAME,
+                    AndroidManifest.ATTRIBUTE_NAME,
                     true /* hasNamespace */);
             if (instrumentationName != null) {
-                String instrClassName = combinePackageAndClassName(mPackage, instrumentationName);
+                String instrClassName = AndroidManifest.combinePackageAndClassName(mPackage,
+                        instrumentationName);
                 String targetPackage = getAttributeValue(attributes,
-                        ManifestConstants.ATTRIBUTE_TARGET_PACKAGE,
+                        AndroidManifest.ATTRIBUTE_TARGET_PACKAGE,
                         true /* hasNamespace */);
                 mInstrumentations.add(new Instrumentation(instrClassName, targetPackage));
                 if (mMarkErrors) {
@@ -954,39 +955,6 @@ public class AndroidManifestParser {
     }
 
     /**
-     * Combines a java package, with a class value from the manifest to make a fully qualified
-     * class name
-     * @param javaPackage the java package from the manifest.
-     * @param className the class name from the manifest.
-     * @return the fully qualified class name.
-     */
-    public static String combinePackageAndClassName(String javaPackage, String className) {
-        if (className == null || className.length() == 0) {
-            return javaPackage;
-        }
-        if (javaPackage == null || javaPackage.length() == 0) {
-            return className;
-        }
-
-        // the class name can be a subpackage (starts with a '.'
-        // char), a simple class name (no dot), or a full java package
-        boolean startWithDot = (className.charAt(0) == '.');
-        boolean hasDot = (className.indexOf('.') != -1);
-        if (startWithDot || hasDot == false) {
-
-            // add the concatenation of the package and class name
-            if (startWithDot) {
-                return javaPackage + className;
-            } else {
-                return javaPackage + '.' + className;
-            }
-        } else {
-            // just add the class as it should be a fully qualified java name.
-            return className;
-        }
-    }
-
-    /**
      * Given a fully qualified activity name (e.g. com.foo.test.MyClass) and given a project
      * package base name (e.g. com.foo), returns the relative activity name that would be used
      * the "name" attribute of an "activity" element.
index 2777328..e00428e 100644 (file)
@@ -53,7 +53,7 @@ public final class KeyboardStateQualifier extends ResourceQualifier {
          * @param value The qualifier value.
          * @return the enum for the qualifier value or null if no matching was found.
          */
-        static KeyboardState getEnum(String value) {
+        public static KeyboardState getEnum(String value) {
             for (KeyboardState orient : values()) {
                 if (orient.mValue.equals(value)) {
                     return orient;
index 9363e87..50cb9cb 100644 (file)
@@ -54,7 +54,7 @@ public final class NavigationMethodQualifier extends ResourceQualifier {
          * @param value The qualifier value.
          * @return the enum for the qualifier value or null if no matching was found.
          */
-        static NavigationMethod getEnum(String value) {
+        public static NavigationMethod getEnum(String value) {
             for (NavigationMethod orient : values()) {
                 if (orient.mValue.equals(value)) {
                     return orient;
index f82a6ff..ed33994 100644 (file)
@@ -61,7 +61,7 @@ public final class PixelDensityQualifier extends ResourceQualifier {
          * @param value The qualifier value.
          * @return the enum for the qualifier value or null if no matching was found.
          */
-        static Density getEnum(String value) {
+        public static Density getEnum(String value) {
             for (Density orient : values()) {
                 if (orient.mValue.equals(value)) {
                     return orient;
index 85d0c03..a78f217 100644 (file)
@@ -51,7 +51,7 @@ public final class ScreenOrientationQualifier extends ResourceQualifier {
          * @param value The qualifier value.
          * @return the enum for the qualifier value or null if no matching was found.
          */
-        static ScreenOrientation getEnum(String value) {
+        public static ScreenOrientation getEnum(String value) {
             for (ScreenOrientation orient : values()) {
                 if (orient.mValue.equals(value)) {
                     return orient;
index 55857fd..08bce4f 100644 (file)
@@ -48,7 +48,7 @@ public class ScreenRatioQualifier extends ResourceQualifier {
          * @param value The qualifier value.
          * @return the enum for the qualifier value or null if no matching was found.
          */
-        static ScreenRatio getEnum(String value) {
+        public static ScreenRatio getEnum(String value) {
             for (ScreenRatio orient : values()) {
                 if (orient.mValue.equals(value)) {
                     return orient;
index d148efc..f48f54d 100644 (file)
@@ -52,7 +52,7 @@ public class ScreenSizeQualifier extends ResourceQualifier {
          * @param value The qualifier value.
          * @return the enum for the qualifier value or null if no matching was found.
          */
-        static ScreenSize getEnum(String value) {
+        public static ScreenSize getEnum(String value) {
             for (ScreenSize orient : values()) {
                 if (orient.mValue.equals(value)) {
                     return orient;
index 6289147..b73776c 100644 (file)
@@ -54,7 +54,7 @@ public final class TextInputMethodQualifier extends ResourceQualifier {
          * @param value The qualifier value.
          * @return the enum for the qualifier value or null if no matching was found.
          */
-        static TextInputMethod getEnum(String value) {
+        public static TextInputMethod getEnum(String value) {
             for (TextInputMethod orient : values()) {
                 if (orient.mValue.equals(value)) {
                     return orient;
index 758c87f..b3bad48 100644 (file)
@@ -52,7 +52,7 @@ public final class TouchScreenQualifier extends ResourceQualifier {
          * @param value The qualifier value.
          * @return the enum for the qualifier value or null if no matching was found.
          */
-        static TouchScreenType getEnum(String value) {
+        public static TouchScreenType getEnum(String value) {
             for (TouchScreenType orient : values()) {
                 if (orient.mValue.equals(value)) {
                     return orient;
index e829f93..f483de8 100644 (file)
 package com.android.ide.eclipse.adt.internal.sdk;
 
 import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
-import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier;
-import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier;
-import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier;
-import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenDimensionQualifier;
-import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier;
-import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenRatioQualifier;
-import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenSizeQualifier;
-import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier;
-import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier;
-import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier.KeyboardState;
-import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier.NavigationMethod;
-import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier.Density;
-import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier.ScreenOrientation;
-import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenRatioQualifier.ScreenRatio;
-import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenSizeQualifier.ScreenSize;
-import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier.TextInputMethod;
-import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier.TouchScreenType;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -64,66 +47,4 @@ public class DeviceConfiguration {
     public Map<String, FolderConfiguration> getConfigs() {
         return mMap;
     }
-
-    /**
-     * temp method returning some hard-coded devices.
-     * TODO: load devices from the SDK and add-ons and remove this method.
-     */
-    public static DeviceConfiguration[] getDevices() {
-        DeviceConfiguration adp1 = new DeviceConfiguration("ADP1");
-        // default config
-        FolderConfiguration defConfig = new FolderConfiguration();
-        defConfig.addQualifier(new ScreenSizeQualifier(ScreenSize.NORMAL));
-        defConfig.addQualifier(new ScreenRatioQualifier(ScreenRatio.NOTLONG));
-        defConfig.addQualifier(new PixelDensityQualifier(Density.MEDIUM));
-        defConfig.addQualifier(new TouchScreenQualifier(TouchScreenType.FINGER));
-        defConfig.addQualifier(new TextInputMethodQualifier(TextInputMethod.QWERTY));
-        defConfig.addQualifier(new NavigationMethodQualifier(NavigationMethod.TRACKBALL));
-        defConfig.addQualifier(new ScreenDimensionQualifier(480, 320));
-
-        // specific configs
-        FolderConfiguration closedLand = new FolderConfiguration();
-        closedLand.set(defConfig);
-        closedLand.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.LANDSCAPE));
-        closedLand.addQualifier(new KeyboardStateQualifier(KeyboardState.HIDDEN));
-        adp1.addConfig("Closed, landscape", closedLand);
-
-        FolderConfiguration closedPort = new FolderConfiguration();
-        closedPort.set(defConfig);
-        closedPort.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.PORTRAIT));
-        closedPort.addQualifier(new KeyboardStateQualifier(KeyboardState.HIDDEN));
-        adp1.addConfig("Closed, portrait", closedPort);
-
-        FolderConfiguration opened = new FolderConfiguration();
-        opened.set(defConfig);
-        opened.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.LANDSCAPE));
-        opened.addQualifier(new KeyboardStateQualifier(KeyboardState.EXPOSED));
-        adp1.addConfig("Opened", opened);
-
-        DeviceConfiguration ion = new DeviceConfiguration("Ion");
-        // default config
-        defConfig = new FolderConfiguration();
-        defConfig.addQualifier(new ScreenSizeQualifier(ScreenSize.NORMAL));
-        defConfig.addQualifier(new ScreenRatioQualifier(ScreenRatio.NOTLONG));
-        defConfig.addQualifier(new PixelDensityQualifier(Density.MEDIUM));
-        defConfig.addQualifier(new TouchScreenQualifier(TouchScreenType.FINGER));
-        defConfig.addQualifier(new KeyboardStateQualifier(KeyboardState.EXPOSED));
-        defConfig.addQualifier(new TextInputMethodQualifier(TextInputMethod.NOKEY));
-        defConfig.addQualifier(new NavigationMethodQualifier(NavigationMethod.TRACKBALL));
-        defConfig.addQualifier(new ScreenDimensionQualifier(480, 320));
-
-        // specific configs
-        FolderConfiguration landscape = new FolderConfiguration();
-        landscape.set(defConfig);
-        landscape.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.LANDSCAPE));
-        ion.addConfig("Landscape", landscape);
-
-        FolderConfiguration portrait = new FolderConfiguration();
-        portrait.set(defConfig);
-        portrait.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.PORTRAIT));
-        ion.addConfig("Portrait", portrait);
-
-        return new DeviceConfiguration[] { adp1, ion };
-
-    }
-}
+ }
index 871020c..69bf18b 100755 (executable)
 package com.android.ide.eclipse.adt.internal.sdk;\r
 \r
 \r
+import org.xml.sax.ErrorHandler;\r
+import org.xml.sax.SAXException;\r
+\r
 import java.io.InputStream;\r
 \r
+import javax.xml.XMLConstants;\r
+import javax.xml.transform.stream.StreamSource;\r
+import javax.xml.validation.Schema;\r
+import javax.xml.validation.SchemaFactory;\r
+import javax.xml.validation.Validator;\r
+\r
 /**\r
- * Public constants for the sdk-repository XML Schema.\r
+ * Public constants for the layout device description XML Schema.\r
  */\r
 public class LayoutConfigsXsd {\r
 \r
@@ -85,8 +94,13 @@ public class LayoutConfigsXsd {
 \r
     public static final String NODE_SCREEN_DIMENSION = "screen-dimension";          //$NON-NLS-1$\r
 \r
+    /** The screen-dimension element has 2 size element children. */\r
     public static final String NODE_SIZE = "size";                                  //$NON-NLS-1$\r
 \r
+    public static final String NODE_XPDI = "xdpi";                                  //$NON-NLS-1$\r
+\r
+    public static final String NODE_YDPI = "ydpi";                                  //$NON-NLS-1$\r
+\r
     /**\r
      * The "name" attribute, used by both the "device" and the "config"\r
      * elements. It represents the user-interface name of these objects.\r
@@ -100,4 +114,17 @@ public class LayoutConfigsXsd {
         return LayoutConfigsXsd.class.getResourceAsStream("layout-configs.xsd");    //$NON-NLS-1$\r
     }\r
 \r
+    /** Helper method that returns a {@link Validator} for our XSD */\r
+    public static Validator getValidator(ErrorHandler handler) throws SAXException {\r
+        InputStream xsdStream = getXsdStream();\r
+        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);\r
+        Schema schema = factory.newSchema(new StreamSource(xsdStream));\r
+        Validator validator = schema.newValidator();\r
+        if (handler != null) {\r
+            validator.setErrorHandler(handler);\r
+        }\r
+\r
+        return validator;\r
+    }\r
+\r
 }\r
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceHandler.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceHandler.java
new file mode 100644 (file)
index 0000000..71d7f18
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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.internal.sdk;
+
+import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
+import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenDimensionQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenRatioQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenSizeQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier.KeyboardState;
+import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier.NavigationMethod;
+import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier.Density;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier.ScreenOrientation;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenRatioQualifier.ScreenRatio;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenSizeQualifier.ScreenSize;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier.TextInputMethod;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier.TouchScreenType;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@link DefaultHandler} implementation to parse Layout Device XML file.
+ * @see LayoutConfigsXsd
+ * @see Layout-configs.xsd
+ */
+class LayoutDeviceHandler extends DefaultHandler {
+    /*
+     * The handler does most of the work in startElement and endElement.
+     * In startElement, it'll create DeviceConfiguration on <device>, as well as
+     * FolderConfiguration instances on <default> and <config>.
+     * Those objects are then filled as new nodes are discovered.
+     *
+     * For the qualifier values, the qualifier is created and added to the current config
+     * on the endElement, by using the content found in characters().
+     */
+
+    private List<DeviceConfiguration> mDevices = new ArrayList<DeviceConfiguration>();
+
+    private DeviceConfiguration mCurrentDevice;
+    private FolderConfiguration mDefaultConfig;
+    private FolderConfiguration mCurrentConfig;
+    private final StringBuilder mStringAccumulator = new StringBuilder();
+
+    private String mSize1, mSize2;
+
+    public List<DeviceConfiguration> getDevices() {
+        return mDevices;
+    }
+
+    @Override
+    public void startElement(String uri, String localName, String name, Attributes attributes)
+            throws SAXException {
+        if (LayoutConfigsXsd.NODE_DEVICE.equals(localName)) {
+            // get the deviceName, will not be null since we validated the XML.
+            String deviceName = attributes.getValue("", LayoutConfigsXsd.ATTR_NAME);
+
+            // create a device and add it to the list
+            mCurrentDevice = new DeviceConfiguration(deviceName);
+            mDevices.add(mCurrentDevice);
+        } else if (LayoutConfigsXsd.NODE_DEFAULT.equals(localName)) {
+            // create a new default config
+            mDefaultConfig = mCurrentConfig = new FolderConfiguration();
+        } else if (LayoutConfigsXsd.NODE_CONFIG.equals(localName)) {
+            // create a new config
+            mCurrentConfig = new FolderConfiguration();
+
+            // init with default config if applicable
+            if (mDefaultConfig != null) {
+                mCurrentConfig.set(mDefaultConfig);
+            }
+
+            // get the name of the config
+            String deviceName = attributes.getValue("", LayoutConfigsXsd.ATTR_NAME);
+
+            // give it to the current device.
+            mCurrentDevice.addConfig(deviceName, mCurrentConfig);
+        } else if (LayoutConfigsXsd.NODE_SCREEN_DIMENSION.equals(localName)) {
+            mSize1 = mSize2 = null;
+        }
+
+        mStringAccumulator.setLength(0);
+    }
+
+    @Override
+    public void characters(char[] ch, int start, int length) throws SAXException {
+        mStringAccumulator.append(ch, start, length);
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String name) throws SAXException {
+        if (LayoutConfigsXsd.NODE_DEVICE.equals(localName)) {
+            mCurrentDevice = null;
+            mDefaultConfig = null;
+        } else if (LayoutConfigsXsd.NODE_CONFIG.equals(localName)) {
+            mCurrentConfig = null;
+        } else if (LayoutConfigsXsd.NODE_SCREEN_SIZE.equals(localName)) {
+            ScreenSizeQualifier ssq = new ScreenSizeQualifier(
+                    ScreenSize.getEnum(mStringAccumulator.toString()));
+            mCurrentConfig.setScreenSizeQualifier(ssq);
+        } else if (LayoutConfigsXsd.NODE_SCREEN_RATIO.equals(localName)) {
+            ScreenRatioQualifier srq = new ScreenRatioQualifier(
+                    ScreenRatio.getEnum(mStringAccumulator.toString()));
+            mCurrentConfig.setScreenRatioQualifier(srq);
+        } else if (LayoutConfigsXsd.NODE_SCREEN_ORIENTATION.equals(localName)) {
+            ScreenOrientationQualifier soq = new ScreenOrientationQualifier(
+                    ScreenOrientation.getEnum(mStringAccumulator.toString()));
+            mCurrentConfig.setScreenOrientationQualifier(soq);
+        } else if (LayoutConfigsXsd.NODE_PIXEL_DENSITY.equals(localName)) {
+            PixelDensityQualifier pdq = new PixelDensityQualifier(
+                    Density.getEnum(mStringAccumulator.toString()));
+            mCurrentConfig.setPixelDensityQualifier(pdq);
+        } else if (LayoutConfigsXsd.NODE_TOUCH_TYPE.equals(localName)) {
+            TouchScreenQualifier tsq = new TouchScreenQualifier(
+                    TouchScreenType.getEnum(mStringAccumulator.toString()));
+            mCurrentConfig.setTouchTypeQualifier(tsq);
+        } else if (LayoutConfigsXsd.NODE_KEYBOARD_STATE.equals(localName)) {
+            KeyboardStateQualifier ksq = new KeyboardStateQualifier(
+                    KeyboardState.getEnum(mStringAccumulator.toString()));
+            mCurrentConfig.setKeyboardStateQualifier(ksq);
+        } else if (LayoutConfigsXsd.NODE_TEXT_INPUT_METHOD.equals(localName)) {
+            TextInputMethodQualifier timq = new TextInputMethodQualifier(
+                    TextInputMethod.getEnum(mStringAccumulator.toString()));
+            mCurrentConfig.setTextInputMethodQualifier(timq);
+        } else if (LayoutConfigsXsd.NODE_NAV_METHOD.equals(localName)) {
+            NavigationMethodQualifier nmq = new NavigationMethodQualifier(
+                    NavigationMethod.getEnum(mStringAccumulator.toString()));
+            mCurrentConfig.setNavigationMethodQualifier(nmq);
+        } else if (LayoutConfigsXsd.NODE_SCREEN_DIMENSION.equals(localName)) {
+            ScreenDimensionQualifier qual = ScreenDimensionQualifier.getQualifier(mSize1, mSize2);
+            if (qual != null) {
+                mCurrentConfig.setScreenDimensionQualifier(qual);
+            }
+        } else if (LayoutConfigsXsd.NODE_SIZE.equals(localName)) {
+            if (mSize1 == null) {
+                mSize1 = mStringAccumulator.toString();
+            } else if (mSize2 == null) {
+                mSize2 = mStringAccumulator.toString();
+            }
+        }
+    }
+}
index f93b6c5..4003d88 100644 (file)
@@ -19,6 +19,24 @@ package com.android.ide.eclipse.adt.internal.sdk;
 import com.android.ddmlib.IDevice;
 import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer;
+import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
+import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenDimensionQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenRatioQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenSizeQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier.KeyboardState;
+import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier.NavigationMethod;
+import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier.Density;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier.ScreenOrientation;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenRatioQualifier.ScreenRatio;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenSizeQualifier.ScreenSize;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier.TextInputMethod;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier.TouchScreenType;
 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor;
 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor.IProjectListener;
 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData.LayoutBridge;
@@ -41,15 +59,31 @@ import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaCore;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Validator;
+
 /**
  * Central point to load, manipulate and deal with the Android SDK. Only one SDK can be used
  * at the same time.
@@ -73,6 +107,8 @@ public class Sdk implements IProjectListener {
             new HashMap<IProject, ApkSettings>();
     private final String mDocBaseUrl;
 
+    private List<DeviceConfiguration> mLayoutDevices = new ArrayList<DeviceConfiguration>();
+
     /**
      * Classes implementing this interface will receive notification when targets are changed.
      */
@@ -432,6 +468,9 @@ public class Sdk implements IProjectListener {
         // pre-compute some paths
         mDocBaseUrl = getDocumentationBaseUrl(mManager.getLocation() +
                 SdkConstants.OS_SDK_DOCS_FOLDER);
+
+        // create some built-in layout devices
+        createDefaultLayoutDevices();
     }
 
     /**
@@ -518,6 +557,173 @@ public class Sdk implements IProjectListener {
         // ignore this. The project will be added to the map the first time the target needs
         // to be resolved.
     }
+
+
+    // ---------- Device Configuration methods ----------
+
+    /**
+     * A SAX error handler that captures the errors and warnings.
+     * This allows us to capture *all* errors and just not get an exception on the first one.
+     */
+    private static class CaptureErrorHandler implements ErrorHandler {
+
+        private final String mSourceLocation;
+
+        private boolean mFoundError = false;
+
+        CaptureErrorHandler(String sourceLocation) {
+            mSourceLocation = sourceLocation;
+        }
+
+        public boolean foundError() {
+            return mFoundError;
+        }
+
+        /**
+         * @throws SAXException
+         */
+        public void error(SAXParseException ex) throws SAXException {
+            mFoundError = true;
+            AdtPlugin.log(ex, "Error validating %1$s", mSourceLocation);
+        }
+
+        /**
+         * @throws SAXException
+         */
+        public void fatalError(SAXParseException ex) throws SAXException {
+            mFoundError = true;
+            AdtPlugin.log(ex, "Error validating %1$s", mSourceLocation);
+        }
+
+        /**
+         * @throws SAXException
+         */
+        public void warning(SAXParseException ex) throws SAXException {
+            // ignore those for now.
+        }
+    }
+
+    /**
+     * Returns the list of {@link DeviceConfiguration} found in the SDK.
+     */
+    public List<DeviceConfiguration> getLayoutDevices() {
+        return mLayoutDevices;
+    }
+
+    /**
+     * Parses the SDK add-ons to look for files called {@link SdkConstants#FN_DEVICES_XML} to
+     * load {@link DeviceConfiguration} from them.
+     */
+    public void parseAddOnLayoutDevices() {
+        SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+        parserFactory.setNamespaceAware(true);
+
+        IAndroidTarget[] targets = mManager.getTargets();
+        for (IAndroidTarget target : targets) {
+            if (target.isPlatform() == false) {
+                File deviceXml = new File(target.getLocation(), SdkConstants.FN_DEVICES_XML);
+                if (deviceXml.isFile()) {
+                    parseLayoutDevices(parserFactory, deviceXml);
+                }
+            }
+        }
+
+        mLayoutDevices = Collections.unmodifiableList(mLayoutDevices);
+    }
+
+    /**
+     * Does the actual parsing of a devices.xml file.
+     */
+    private void parseLayoutDevices(SAXParserFactory parserFactory, File deviceXml) {
+        // first we validate the XML
+        try {
+            Source source = new StreamSource(new FileReader(deviceXml));
+
+            CaptureErrorHandler errorHandler = new CaptureErrorHandler(deviceXml.getAbsolutePath());
+
+            Validator validator = LayoutConfigsXsd.getValidator(errorHandler);
+            validator.validate(source);
+
+            if (errorHandler.foundError() == false) {
+                // do the actual parsing
+                LayoutDeviceHandler handler = new LayoutDeviceHandler();
+
+                SAXParser parser = parserFactory.newSAXParser();
+                parser.parse(new InputSource(new FileInputStream(deviceXml)), handler);
+
+                // get the parsed devices
+                mLayoutDevices.addAll(handler.getDevices());
+            }
+        } catch (SAXException e) {
+            AdtPlugin.log(e, "Error parsing %1$s", deviceXml.getAbsoluteFile());
+        } catch (FileNotFoundException e) {
+            // this shouldn't happen as we check above.
+        } catch (IOException e) {
+            AdtPlugin.log(e, "Error reading %1$s", deviceXml.getAbsoluteFile());
+        } catch (ParserConfigurationException e) {
+            AdtPlugin.log(e, "Error parsing %1$s", deviceXml.getAbsoluteFile());
+        }
+    }
+
+    /**
+     * Creates some built-it layout devices.
+     */
+    private void createDefaultLayoutDevices() {
+        DeviceConfiguration adp1 = new DeviceConfiguration("ADP1");
+        mLayoutDevices.add(adp1);
+        // default config
+        FolderConfiguration defConfig = new FolderConfiguration();
+        defConfig.addQualifier(new ScreenSizeQualifier(ScreenSize.NORMAL));
+        defConfig.addQualifier(new ScreenRatioQualifier(ScreenRatio.NOTLONG));
+        defConfig.addQualifier(new PixelDensityQualifier(Density.MEDIUM));
+        defConfig.addQualifier(new TouchScreenQualifier(TouchScreenType.FINGER));
+        defConfig.addQualifier(new KeyboardStateQualifier(KeyboardState.SOFT));
+        defConfig.addQualifier(new TextInputMethodQualifier(TextInputMethod.QWERTY));
+        defConfig.addQualifier(new NavigationMethodQualifier(NavigationMethod.TRACKBALL));
+        defConfig.addQualifier(new ScreenDimensionQualifier(480, 320));
+
+        // specific configs
+        FolderConfiguration closedPort = new FolderConfiguration();
+        closedPort.set(defConfig);
+        closedPort.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.PORTRAIT));
+        adp1.addConfig("Portrait, closed", closedPort);
+
+        FolderConfiguration closedLand = new FolderConfiguration();
+        closedLand.set(defConfig);
+        closedLand.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.LANDSCAPE));
+        adp1.addConfig("Landscape, closed", closedLand);
+
+        FolderConfiguration opened = new FolderConfiguration();
+        opened.set(defConfig);
+        opened.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.LANDSCAPE));
+        opened.addQualifier(new KeyboardStateQualifier(KeyboardState.EXPOSED));
+        adp1.addConfig("Landscape, opened", opened);
+
+        DeviceConfiguration ion = new DeviceConfiguration("Ion");
+        mLayoutDevices.add(ion);
+        // default config
+        defConfig = new FolderConfiguration();
+        defConfig.addQualifier(new ScreenSizeQualifier(ScreenSize.NORMAL));
+        defConfig.addQualifier(new ScreenRatioQualifier(ScreenRatio.NOTLONG));
+        defConfig.addQualifier(new PixelDensityQualifier(Density.MEDIUM));
+        defConfig.addQualifier(new TouchScreenQualifier(TouchScreenType.FINGER));
+        defConfig.addQualifier(new KeyboardStateQualifier(KeyboardState.EXPOSED));
+        defConfig.addQualifier(new TextInputMethodQualifier(TextInputMethod.NOKEY));
+        defConfig.addQualifier(new NavigationMethodQualifier(NavigationMethod.TRACKBALL));
+        defConfig.addQualifier(new ScreenDimensionQualifier(480, 320));
+
+        // specific configs
+        FolderConfiguration landscape = new FolderConfiguration();
+        landscape.set(defConfig);
+        landscape.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.LANDSCAPE));
+        ion.addConfig("Landscape", landscape);
+
+        FolderConfiguration portrait = new FolderConfiguration();
+        portrait.set(defConfig);
+        portrait.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.PORTRAIT));
+        ion.addConfig("Portrait", portrait);
+    }
 }
 
 
+
index e045229..49131fb 100755 (executable)
@@ -24,7 +24,7 @@
 
     <xsd:element name="layout-configs">
         <xsd:annotation>
-            <xsd:documentation>
+            <xsd:documentation xml:lang="en">
                 The "layout-configs" element is the root element of this schema.
 
                 It must contain one or more "device" elements that each define the configurations
@@ -41,7 +41,7 @@
                 <xsd:element name="device" minOccurs="1" maxOccurs="unbounded">
 
                     <xsd:annotation>
-                        <xsd:documentation>
+                        <xsd:documentation xml:lang="en">
                             A device element must contain at most one "default" element
                             followed by one or more "config" elements.
 
     -->
     <xsd:complexType name="parametersType">
         <xsd:annotation>
-            <xsd:documentation>
+            <xsd:documentation xml:lang="en">
                 The parametersType define all the parameters that can happen either in a
                 "default" element or in a named "config" element.
                 Each parameter element can appear once at most.
+
+                Parameters here are the same as those used to specify alternate Android
+                resources, as documented by
+                http://d.android.com/guide/topics/resources/resources-i18n.html#AlternateResources
             </xsd:documentation>
         </xsd:annotation>
 
             <!-- parametersType says that 0..1 of each of these elements must be declared. -->
 
             <xsd:element name="screen-size" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies that the configuration is for a particular class of screen.
+                    </xsd:documentation>
+                </xsd:annotation>
                 <xsd:simpleType>
                     <xsd:restriction base="xsd:token">
                         <xsd:enumeration value="small" />
-                        <xsd:enumeration value="medium" />
+                        <xsd:enumeration value="normal" />
                         <xsd:enumeration value="large" />
                     </xsd:restriction>
                 </xsd:simpleType>
             </xsd:element>
 
             <xsd:element name="screen-ratio" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies that the configuration is for a taller/wider than traditional
+                        screen. This is based purely on the aspect ration of the screen: QVGA,
+                        HVGA, and VGA are notlong; WQVGA, WVGA, FWVGA are long. Note that long
+                        may mean either wide or tall, depending on the current orientation.
+                    </xsd:documentation>
+                </xsd:annotation>
                 <xsd:simpleType>
                     <xsd:restriction base="xsd:token">
                         <xsd:enumeration value="long" />
             </xsd:element>
 
             <xsd:element name="screen-orientation" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies that the configuration is for a screen that is tall (port) or
+                        wide (land).
+                    </xsd:documentation>
+                </xsd:annotation>
                 <xsd:simpleType>
                     <xsd:restriction base="xsd:token">
                         <xsd:enumeration value="port" />
             </xsd:element>
 
             <xsd:element name="pixel-density" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the screen density the configuration is defined for. The medium
+                        density of traditional HVGA screens (mdpi) is defined to be approximately
+                        160dpi; low density (ldpi) is 120, and high density (hdpi) is 240. There
+                        is thus a 4:3 scaling factor between each density, so a 9x9 bitmap in ldpi
+                        would be 12x12 is mdpi and 16x16 in hdpi.
+                        The special nodpi density that can be used in resource qualifiers is not
+                        a valid keyword here.
+                    </xsd:documentation>
+                </xsd:annotation>
                 <xsd:simpleType>
                     <xsd:restriction base="xsd:token">
                         <xsd:enumeration value="ldpi" />
             </xsd:element>
 
             <xsd:element name="touch-type" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the touch type the configuration is defined for.
+                    </xsd:documentation>
+                </xsd:annotation>
                 <xsd:simpleType>
                     <xsd:restriction base="xsd:token">
                         <xsd:enumeration value="notouch" />
             </xsd:element>
 
             <xsd:element name="keyboard-state" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        If your configuration uses a soft keyboard, use the keyssoft value.
+                        If it doesn't and has a real keyboard, use keysexposed or keyshidden.
+                    </xsd:documentation>
+                </xsd:annotation>
                 <xsd:simpleType>
                     <xsd:restriction base="xsd:token">
                         <xsd:enumeration value="keysexposed" />
             </xsd:element>
 
             <xsd:element name="text-input-method" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the primary text input method the configuration is designed for.
+                    </xsd:documentation>
+                </xsd:annotation>
                 <xsd:simpleType>
                     <xsd:restriction base="xsd:token">
                         <xsd:enumeration value="nokeys" />
             </xsd:element>
 
             <xsd:element name="nav-method" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the primary non-touchscreen navigation method the configuration
+                        is designed for.
+                    </xsd:documentation>
+                </xsd:annotation>
                 <xsd:simpleType>
                     <xsd:restriction base="xsd:token">
                         <xsd:enumeration value="dpad" />
             </xsd:element>
 
             <xsd:element name="screen-dimension" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the device screen resolution, in pixels.
+                    </xsd:documentation>
+                </xsd:annotation>
                 <xsd:complexType>
                     <xsd:sequence minOccurs="2" maxOccurs="2">
 
                     </xsd:sequence>
                 </xsd:complexType>
             </xsd:element>
+
+            <xsd:element name="xdpi" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the actual density in X of the device screen.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:float">
+                        <xsd:minExclusive value="0" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="ydpi" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the actual density in Y of the device screen.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:float">
+                        <xsd:minExclusive value="0" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
         </xsd:all>
     </xsd:complexType>
 
index f4ad1bb..43b0507 100755 (executable)
@@ -23,11 +23,8 @@ import org.xml.sax.SAXParseException;
 import java.io.InputStream;\r
 import java.io.StringReader;\r
 \r
-import javax.xml.XMLConstants;\r
 import javax.xml.transform.Source;\r
 import javax.xml.transform.stream.StreamSource;\r
-import javax.xml.validation.Schema;\r
-import javax.xml.validation.SchemaFactory;\r
 import javax.xml.validation.Validator;\r
 \r
 import junit.framework.TestCase;\r
@@ -107,19 +104,42 @@ public class TestLayoutConfisXsd extends TestCase {
 \r
     // --- Helpers ------------\r
 \r
-    /** Helper method that returns a validator for our XSD */\r
-    private Validator getValidator(CaptureErrorHandler handler) throws SAXException {\r
-        InputStream xsdStream = LayoutConfigsXsd.getXsdStream();\r
-        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);\r
-        Schema schema = factory.newSchema(new StreamSource(xsdStream));\r
-        Validator validator = schema.newValidator();\r
-        if (handler != null) {\r
-            validator.setErrorHandler(handler);\r
+    /** An helper that validates a string against an expected regexp. */\r
+    private void assertRegex(String expectedRegexp, String actualString) {\r
+        assertNotNull(actualString);\r
+        assertTrue(\r
+                String.format("Regexp Assertion Failed:\nExpected: %s\nActual: %s\n",\r
+                        expectedRegexp, actualString),\r
+                actualString.matches(expectedRegexp));\r
+    }\r
+\r
+    public void checkFailure(String document, String regexp) throws Exception {\r
+        Source source = new StreamSource(new StringReader(document));\r
+\r
+        // don't capture the validator errors, we want it to fail and catch the exception\r
+        Validator validator = LayoutConfigsXsd.getValidator(null);\r
+        try {\r
+            validator.validate(source);\r
+        } catch (SAXParseException e) {\r
+            // We expect a parse expression referring to this grammar rule\r
+            assertRegex(regexp, e.getMessage());\r
+            return;\r
         }\r
+        // If we get here, the validator has not failed as we expected it to.\r
+        fail();\r
+    }\r
 \r
-        return validator;\r
+    public void checkSuccess(String document) throws Exception {\r
+        Source source = new StreamSource(new StringReader(document));\r
+\r
+        CaptureErrorHandler handler = new CaptureErrorHandler();\r
+        Validator validator = LayoutConfigsXsd.getValidator(null);\r
+        validator.validate(source);\r
+        handler.verify();\r
     }\r
 \r
+    // --- Tests ------------\r
+\r
     /** Validate a valid sample using an InputStream */\r
     public void testValidateLocalRepositoryFile() throws Exception {\r
 \r
@@ -128,176 +148,185 @@ public class TestLayoutConfisXsd extends TestCase {
         Source source = new StreamSource(xmlStream);\r
 \r
         CaptureErrorHandler handler = new CaptureErrorHandler();\r
-        Validator validator = getValidator(handler);\r
+        Validator validator = LayoutConfigsXsd.getValidator(handler);\r
         validator.validate(source);\r
         handler.verify();\r
     }\r
 \r
-    /** An helper that validates a string against an expected regexp. */\r
-    private void assertRegex(String expectedRegexp, String actualString) {\r
-        assertNotNull(actualString);\r
-        assertTrue(\r
-                String.format("Regexp Assertion Failed:\nExpected: %s\nActual: %s\n",\r
-                        expectedRegexp, actualString),\r
-                actualString.matches(expectedRegexp));\r
-    }\r
-\r
-    // --- Tests ------------\r
-\r
     /** A document should at least have a root to be valid */\r
     public void testEmptyXml() throws Exception {\r
-        String document = "<?xml version=\"1.0\"?>";\r
-\r
-        Source source = new StreamSource(new StringReader(document));\r
+        checkFailure(\r
+                // document\r
+                "<?xml version=\"1.0\"?>",\r
 \r
-        CaptureErrorHandler handler = new CaptureErrorHandler();\r
-        Validator validator = getValidator(handler);\r
-\r
-        try {\r
-            validator.validate(source);\r
-        } catch (SAXParseException e) {\r
-            // We expect to get this specific exception message\r
-            assertRegex("Premature end of file.*", e.getMessage());\r
-            return;\r
-        }\r
-        // We shouldn't get here\r
-        handler.verify();\r
-        fail();\r
+                // expected failure\r
+                "Premature end of file.*");\r
     }\r
 \r
     /** A document with an unknown element. */\r
     public void testUnknownContentXml() throws Exception {\r
-        String document = "<?xml version=\"1.0\"?>" +\r
-            "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
-            "<d:unknown />" +\r
-            "</d:layout-configs>";\r
-\r
-        Source source = new StreamSource(new StringReader(document));\r
-\r
-        // don't capture the validator errors, we want it to fail and catch the exception\r
-        Validator validator = getValidator(null);\r
-        try {\r
-            validator.validate(source);\r
-        } catch (SAXParseException e) {\r
-            // We expect a parse expression referring to this grammar rule\r
-            assertRegex("cvc-complex-type.2.4.a: Invalid content was found.*", e.getMessage());\r
-            return;\r
-        }\r
-        // If we get here, the validator has not failed as we expected it to.\r
-        fail();\r
+        checkFailure(\r
+                // document\r
+                "<?xml version=\"1.0\"?>" +\r
+                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
+                "<d:unknown />" +\r
+                "</d:layout-configs>",\r
+\r
+                // expected failure\r
+                "cvc-complex-type.2.4.a: Invalid content was found.*");\r
     }\r
 \r
     /** A document with an missing attribute in a device element. */\r
     public void testIncompleteContentXml() throws Exception {\r
-        String document = "<?xml version=\"1.0\"?>" +\r
-            "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
-            "<d:device />" +\r
-            "</d:layout-configs>";\r
-\r
-        Source source = new StreamSource(new StringReader(document));\r
-\r
-        // don't capture the validator errors, we want it to fail and catch the exception\r
-        Validator validator = getValidator(null);\r
-        try {\r
-            validator.validate(source);\r
-        } catch (SAXParseException e) {\r
-            // We expect a parse error referring to this grammar rule\r
-            assertRegex("cvc-complex-type.4: Attribute 'name' must appear on element 'd:device'.", e.getMessage());\r
-            return;\r
-        }\r
-        // If we get here, the validator has not failed as we expected it to.\r
-        fail();\r
+        checkFailure(\r
+                // document\r
+                "<?xml version=\"1.0\"?>" +\r
+                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
+                "<d:device />" +\r
+                "</d:layout-configs>",\r
+\r
+                // expected failure\r
+                "cvc-complex-type.4: Attribute 'name' must appear on element 'd:device'.");\r
     }\r
 \r
     /** A document with a root element containing no device element is not valid. */\r
     public void testEmptyRootXml() throws Exception {\r
-        String document = "<?xml version=\"1.0\"?>" +\r
-            "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" />";\r
-\r
-        Source source = new StreamSource(new StringReader(document));\r
+        checkFailure(\r
+                // document\r
+                "<?xml version=\"1.0\"?>" +\r
+                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" />",\r
 \r
-        // don't capture the validator errors, we want it to fail and catch the exception\r
-        Validator validator = getValidator(null);\r
-        try {\r
-            validator.validate(source);\r
-        } catch (SAXParseException e) {\r
-            // We expect a parse expression referring to this grammar rule\r
-            assertRegex("cvc-complex-type.2.4.b: The content of element 'd:layout-configs' is not complete.*", e.getMessage());\r
-            return;\r
-        }\r
-        // If we get here, the validator has not failed as we expected it to.\r
-        fail();\r
+                // expected failure\r
+                "cvc-complex-type.2.4.b: The content of element 'd:layout-configs' is not complete.*");\r
     }\r
 \r
     /** A document with an empty device element is not valid. */\r
     public void testEmptyDeviceXml() throws Exception {\r
-        String document = "<?xml version=\"1.0\"?>" +\r
-            "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
-            "<d:device name=\"foo\"/>" +\r
-            "</d:layout-configs>";\r
-\r
-        Source source = new StreamSource(new StringReader(document));\r
-\r
-        // don't capture the validator errors, we want it to fail and catch the exception\r
-        Validator validator = getValidator(null);\r
-        try {\r
-            validator.validate(source);\r
-        } catch (SAXParseException e) {\r
-            // We expect a parse error referring to this grammar rule\r
-            assertRegex("cvc-complex-type.2.4.b: The content of element 'd:device' is not complete.*", e.getMessage());\r
-            return;\r
-        }\r
-        // If we get here, the validator has not failed as we expected it to.\r
-        fail();\r
+        checkFailure(\r
+                // document\r
+                "<?xml version=\"1.0\"?>" +\r
+                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
+                "<d:device name=\"foo\"/>" +\r
+                "</d:layout-configs>",\r
+\r
+                // expected failure\r
+                "cvc-complex-type.2.4.b: The content of element 'd:device' is not complete.*");\r
     }\r
 \r
     /** A document with two default elements in a device element is not valid. */\r
     public void testTwoDefaultsXml() throws Exception {\r
-        String document = "<?xml version=\"1.0\"?>" +\r
-            "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
-            "<d:device name=\"foo\">" +\r
-            "  <d:default />" +\r
-            "  <d:default />" +\r
-            "</d:device>" +\r
-            "</d:layout-configs>";\r
-\r
-        Source source = new StreamSource(new StringReader(document));\r
-\r
-        // don't capture the validator errors, we want it to fail and catch the exception\r
-        Validator validator = getValidator(null);\r
-        try {\r
-            validator.validate(source);\r
-        } catch (SAXParseException e) {\r
-            // We expect a parse error referring to this grammar rule\r
-            assertRegex("cvc-complex-type.2.4.a: Invalid content was found starting with element 'd:default'.*", e.getMessage());\r
-            return;\r
-        }\r
-        // If we get here, the validator has not failed as we expected it to.\r
-        fail();\r
+        checkFailure(\r
+                // document\r
+                "<?xml version=\"1.0\"?>" +\r
+                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
+                "<d:device name=\"foo\">" +\r
+                "  <d:default />" +\r
+                "  <d:default />" +\r
+                "</d:device>" +\r
+                "</d:layout-configs>",\r
+\r
+                // expected failure\r
+                "cvc-complex-type.2.4.a: Invalid content was found starting with element 'd:default'.*");\r
     }\r
 \r
     /** The default elements must be defined before the config one. It's invalid if after. */\r
     public void testDefaultConfigOrderXml() throws Exception {\r
-        String document = "<?xml version=\"1.0\"?>" +\r
-            "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
-            "<d:device name=\"foo\">" +\r
-            "  <d:config name=\"must-be-after-default\" />" +\r
-            "  <d:default />" +\r
-            "</d:device>" +\r
-            "</d:layout-configs>";\r
+        checkFailure(\r
+                // document\r
+                "<?xml version=\"1.0\"?>" +\r
+                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
+                "<d:device name=\"foo\">" +\r
+                "  <d:config name=\"must-be-after-default\" />" +\r
+                "  <d:default />" +\r
+                "</d:device>" +\r
+                "</d:layout-configs>",\r
+\r
+                // expected failure\r
+                "cvc-complex-type.2.4.a: Invalid content was found starting with element 'd:default'.*");\r
+    }\r
 \r
-        Source source = new StreamSource(new StringReader(document));\r
+    /** Screen dimension cannot be 0. */\r
+    public void testScreenDimZeroXml() throws Exception {\r
+        checkFailure(\r
+                // document\r
+                "<?xml version=\"1.0\"?>" +\r
+                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
+                "<d:device name=\"foo\">" +\r
+                "  <d:default>" +\r
+                "    <d:screen-dimension> <d:size>0</d:size> <d:size>1</d:size> </d:screen-dimension>" +\r
+                "  </d:default>" +\r
+                "</d:device>" +\r
+                "</d:layout-configs>",\r
+\r
+                // expected failure\r
+                "cvc-minInclusive-valid: Value '0' is not facet-valid with respect to minInclusive '1'.*");\r
+    }\r
 \r
-        // don't capture the validator errors, we want it to fail and catch the exception\r
-        Validator validator = getValidator(null);\r
-        try {\r
-            validator.validate(source);\r
-        } catch (SAXParseException e) {\r
-            // We expect a parse error referring to this grammar rule\r
-            assertRegex("cvc-complex-type.2.4.a: Invalid content was found starting with element 'd:default'.*", e.getMessage());\r
-            return;\r
-        }\r
-        // If we get here, the validator has not failed as we expected it to.\r
-        fail();\r
+    /** Screen dimension cannot be negative. */\r
+    public void testScreenDimNegativeXml() throws Exception {\r
+        checkFailure(\r
+                // document\r
+                "<?xml version=\"1.0\"?>" +\r
+                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
+                "<d:device name=\"foo\">" +\r
+                "  <d:default>" +\r
+                "    <d:screen-dimension> <d:size>-5</d:size> <d:size>1</d:size> </d:screen-dimension>" +\r
+                "  </d:default>" +\r
+                "</d:device>" +\r
+                "</d:layout-configs>",\r
+\r
+                // expected failure\r
+                "cvc-minInclusive-valid: Value '-5' is not facet-valid with respect to minInclusive '1'.*");\r
+    }\r
+\r
+    /** X/Y dpi cannot be 0. */\r
+    public void testXDpiZeroXml() throws Exception {\r
+        checkFailure(\r
+                // document\r
+                "<?xml version=\"1.0\"?>" +\r
+                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
+                "<d:device name=\"foo\">" +\r
+                "  <d:default>" +\r
+                "    <d:xdpi>0</d:xdpi>" +\r
+                "  </d:default>" +\r
+                "</d:device>" +\r
+                "</d:layout-configs>",\r
+\r
+                // expected failure\r
+                "cvc-minExclusive-valid: Value '0' is not facet-valid with respect to minExclusive '0.0E1'.*");\r
     }\r
+\r
+\r
+    /** X/Y dpi cannot be negative. */\r
+    public void testXDpiNegativeXml() throws Exception {\r
+        checkFailure(\r
+                // document\r
+                "<?xml version=\"1.0\"?>" +\r
+                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
+                "<d:device name=\"foo\">" +\r
+                "  <d:default>" +\r
+                "    <d:xdpi>-3.1415926538</d:xdpi>" +\r
+                "  </d:default>" +\r
+                "</d:device>" +\r
+                "</d:layout-configs>",\r
+\r
+                // expected failure\r
+                "cvc-minExclusive-valid: Value '-3.1415926538' is not facet-valid with respect to minExclusive '0.0E1'.*");\r
+    }\r
+\r
+    /** WHitespace around token is accepted by the schema. */\r
+    public void testTokenWhitespaceXml() throws Exception {\r
+        checkSuccess(\r
+                // document\r
+                "<?xml version=\"1.0\"?>" +\r
+                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +\r
+                "<d:device name=\"foo\">" +\r
+                "  <d:config name='foo'>" +\r
+                "    <d:screen-ratio>  \n long \r </d:screen-ratio>" +\r
+                "  </d:config>" +\r
+                "</d:device>" +\r
+                "</d:layout-configs>");\r
+    }\r
+\r
 }\r
+\r
index 29f48cd..901dd71 100755 (executable)
@@ -32,6 +32,8 @@
                 <d:size>240</d:size>    <!-- 2 * int>0 -->\r
                 <d:size>480</d:size>\r
             </d:screen-dimension>\r
+            <d:xdpi>180.81234</d:xdpi>\r
+            <d:ydpi>180.81234</d:ydpi>\r
         </d:default>\r
 \r
         <d:config name="Portrait">\r
@@ -50,8 +52,8 @@
         <d:config name="screen-size-small">\r
             <d:screen-size>small</d:screen-size>\r
         </d:config>\r
-        <d:config name="screen-size-medium">\r
-            <d:screen-size>medium</d:screen-size>\r
+        <d:config name="screen-size-normal">\r
+            <d:screen-size>normal</d:screen-size>\r
         </d:config>\r
         <d:config name="screen-size-large">\r
             <d:screen-size>large</d:screen-size>\r
             <d:nav-method>nonav</d:nav-method>\r
         </d:config>\r
 \r
-    </d:device>\r
+        <d:config name="xdpi">\r
+            <d:xdpi>240</d:xdpi>\r
+        </d:config>\r
+        <d:config name="ydpi">\r
+            <d:ydpi>2800</d:ydpi>\r
+        </d:config>\r
 \r
+    </d:device>\r
 \r
     <d:device name="SomePhone">       <!-- 1..n -->\r
-        <d:config name="screen-size-medium">\r
-            <d:screen-size>medium</d:screen-size>\r
+        <d:config name="screen-size-normal">\r
+            <d:screen-size>normal</d:screen-size>\r
         </d:config>\r
     </d:device>\r
 \r
index 14e0080..2b9aca3 100644 (file)
 package com.android.ide.eclipse.tests.functests.layoutRendering;
 
 import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
+import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenDimensionQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenRatioQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenSizeQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier.KeyboardState;
+import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier.NavigationMethod;
+import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier.Density;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier.ScreenOrientation;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenRatioQualifier.ScreenRatio;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenSizeQualifier.ScreenSize;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier.TextInputMethod;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier.TouchScreenType;
 import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
@@ -205,6 +222,7 @@ public class ApiDemosRenderingTest extends FuncTestCase {
                     null /*projectKey*/,
                     320,
                     480,
+                    false, //renderFullSize
                     160, //density
                     160, //xdpi
                     160, // ydpi
@@ -234,9 +252,26 @@ public class ApiDemosRenderingTest extends FuncTestCase {
         }
     }
 
+    /**
+     * Returns a config. This must be a valid config like a device would return. This is to
+     * prevent issues where some resources don't exist in all cases and not in the default
+     * (for instance only available in hdpi and mdpi but not in default).
+     * @return
+     */
     private FolderConfiguration getConfiguration() {
         FolderConfiguration config = new FolderConfiguration();
 
+        // this matches an ADP1.
+        config.addQualifier(new ScreenSizeQualifier(ScreenSize.NORMAL));
+        config.addQualifier(new ScreenRatioQualifier(ScreenRatio.NOTLONG));
+        config.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.PORTRAIT));
+        config.addQualifier(new PixelDensityQualifier(Density.MEDIUM));
+        config.addQualifier(new TouchScreenQualifier(TouchScreenType.FINGER));
+        config.addQualifier(new KeyboardStateQualifier(KeyboardState.HIDDEN));
+        config.addQualifier(new TextInputMethodQualifier(TextInputMethod.QWERTY));
+        config.addQualifier(new NavigationMethodQualifier(NavigationMethod.TRACKBALL));
+        config.addQualifier(new ScreenDimensionQualifier(480, 320));
+
         return config;
     }
 }
index 23107a1..658d4d2 100644 (file)
@@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.internal.editors.resources.configurations;
 
 import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
 import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier.Density;
 
 import junit.framework.TestCase;
 
@@ -41,16 +42,16 @@ public class PixelDensityQualifierTest extends TestCase {
     }
 
     public void testCheckAndSet() {
-        assertEquals(true, pdq.checkAndSet("123dpi", config));//$NON-NLS-1$
+        assertEquals(true, pdq.checkAndSet("ldpi", config));//$NON-NLS-1$
         assertTrue(config.getPixelDensityQualifier() != null);
-        assertEquals(123, config.getPixelDensityQualifier().getValue());
-        assertEquals("123dpi", config.getPixelDensityQualifier().toString()); //$NON-NLS-1$
+        assertEquals(Density.LOW, config.getPixelDensityQualifier().getValue());
+        assertEquals("ldpi", config.getPixelDensityQualifier().toString()); //$NON-NLS-1$
     }
 
     public void testFailures() {
         assertEquals(false, pdq.checkAndSet("", config));//$NON-NLS-1$
         assertEquals(false, pdq.checkAndSet("dpi", config));//$NON-NLS-1$
-        assertEquals(false, pdq.checkAndSet("123DPI", config));//$NON-NLS-1$
+        assertEquals(false, pdq.checkAndSet("123dpi", config));//$NON-NLS-1$
         assertEquals(false, pdq.checkAndSet("123", config));//$NON-NLS-1$
         assertEquals(false, pdq.checkAndSet("sdfdpi", config));//$NON-NLS-1$
     }
index 7601648..c0533ed 100644 (file)
@@ -88,13 +88,16 @@ public class ConfigMatchTest extends TestCase {
                 null, // network code
                 null, // language
                 null, // region
+                null, // screen size
+                null, // screen ratio
                 null, // screen orientation
                 null, // dpi
                 null, // touch mode
                 null, // keyboard state
                 null, // text input
                 null, // navigation
-                null); // screen size
+                null, // screen dimension
+                null);// version
 
         addFolder(mResources, defaultConfig, validMemberList);
 
@@ -103,13 +106,16 @@ public class ConfigMatchTest extends TestCase {
                 null, // network code
                 "en", // language
                 null, // region
+                null, // screen size
+                null, // screen ratio
                 null, // screen orientation
                 null, // dpi
                 null, // touch mode
                 KeyboardState.EXPOSED.getValue(), // keyboard state
                 null, // text input
                 null, // navigation
-                null); // screen size
+                null, // screen dimension
+                null);// version
 
         addFolder(mResources, config1, validMemberList);
 
@@ -118,13 +124,16 @@ public class ConfigMatchTest extends TestCase {
                 null, // network code
                 "en", // language
                 null, // region
+                null, // screen size
+                null, // screen ratio
                 null, // screen orientation
                 null, // dpi
                 null, // touch mode
                 KeyboardState.HIDDEN.getValue(), // keyboard state
                 null, // text input
                 null, // navigation
-                null); // screen size
+                null, // screen dimension
+                null);// version
 
         addFolder(mResources, config2, validMemberList);
 
@@ -133,13 +142,16 @@ public class ConfigMatchTest extends TestCase {
                 null, // network code
                 "en", // language
                 null, // region
+                null, // screen size
+                null, // screen ratio
                 ScreenOrientation.LANDSCAPE.getValue(), // screen orientation
                 null, // dpi
                 null, // touch mode
                 null, // keyboard state
                 null, // text input
                 null, // navigation
-                null); // screen size
+                null, // screen dimension
+                null);// version
 
         addFolder(mResources, config3, validMemberList);
 
@@ -148,13 +160,16 @@ public class ConfigMatchTest extends TestCase {
                 "mnc435", // network code
                 "en", // language
                 "rUS", // region
+                "normal", // screen size
+                "notlong", // screen ratio
                 ScreenOrientation.LANDSCAPE.getValue(), // screen orientation
-                "160dpi", // dpi
+                "mdpi", // dpi
                 TouchScreenType.FINGER.getValue(), // touch mode
                 KeyboardState.EXPOSED.getValue(), // keyboard state
                 TextInputMethod.QWERTY.getValue(), // text input
                 NavigationMethod.DPAD.getValue(), // navigation
-                "480x320"); // screen size
+                "480x320", // screen dimension
+                "v3"); // version
 
         addFolder(mResources, config4, invalidMemberList);
     }
@@ -171,13 +186,16 @@ public class ConfigMatchTest extends TestCase {
                 "mnc435", // network code
                 "en", // language
                 "rUS", // region
+                "normal", // screen size
+                "notlong", // screen ratio
                 ScreenOrientation.LANDSCAPE.getValue(), // screen orientation
-                "160dpi", // dpi
+                "mdpi", // dpi
                 TouchScreenType.FINGER.getValue(), // touch mode
                 KeyboardState.EXPOSED.getValue(), // keyboard state
                 TextInputMethod.QWERTY.getValue(), // text input
                 NavigationMethod.DPAD.getValue(), // navigation
-                "480x320"); // screen size
+                "480x320", // screen dimension
+                "v3"); // version
 
         ResourceFile result = mResources.getMatchingFile(SEARCHED_FILENAME,
                 ResourceFolderType.LAYOUT, testConfig);
index 2b06e76..9b07072 100644 (file)
@@ -4,7 +4,7 @@
       android:versionCode="1"
       android:versionName="1.0">
     <application android:label="@string/app_name">
-        <activity android:name=".ACTIVITY_NAME"
+        <activity android:name="ACTIVITY_ENTRY_NAME"
                   android:label="@string/app_name">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
index 1f7d827..c74ff6d 100644 (file)
@@ -17,5 +17,5 @@
     -->
     <instrumentation android:name="android.test.InstrumentationTestRunner"
                      android:targetPackage="PACKAGE"
-                     android:label="Tests for ACTIVITY_NAME"/>
+                     android:label="Tests for PACKAGE"/>
 </manifest>
diff --git a/tools/scripts/iml.template b/tools/scripts/iml.template
deleted file mode 100644 (file)
index c4fe3a3..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module version="4" relativePaths="true" type="JAVA_MODULE">
-  <component name="ModuleRootManager" />
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$">
-      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
-    </content>
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="library" name="android" level="project" />
-    <orderEntry type="inheritedJdk" />
-    <orderEntryProperties />
-  </component>
-</module>
diff --git a/tools/scripts/ipr.template b/tools/scripts/ipr.template
deleted file mode 100644 (file)
index cb3d65e..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4" relativePaths="false">
-  <component name="AntConfiguration">
-    <defaultAnt bundledAnt="true" />
-    <buildFile url="file://$PROJECT_DIR$/build.xml">
-      <additionalClassPath />
-      <antReference projectDefault="true" />
-      <customJdkName value="" />
-      <maximumHeapSize value="128" />
-      <properties />
-    </buildFile>
-  </component>
-  <component name="BuildJarProjectSettings">
-    <option name="BUILD_JARS_ON_MAKE" value="false" />
-  </component>
-  <component name="CodeStyleProjectProfileManger">
-    <option name="PROJECT_PROFILE" />
-    <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
-  </component>
-  <component name="CodeStyleSettingsManager">
-    <option name="PER_PROJECT_SETTINGS" />
-    <option name="USE_PER_PROJECT_SETTINGS" value="false" />
-  </component>
-  <component name="CompilerConfiguration">
-    <option name="DEFAULT_COMPILER" value="Javac" />
-    <option name="DEPLOY_AFTER_MAKE" value="0" />
-    <resourceExtensions>
-      <entry name=".+\.(properties|xml|html|dtd|tld)" />
-      <entry name=".+\.(gif|png|jpeg|jpg)" />
-    </resourceExtensions>
-    <wildcardResourcePatterns>
-      <entry name="?*.properties" />
-      <entry name="?*.xml" />
-      <entry name="?*.gif" />
-      <entry name="?*.png" />
-      <entry name="?*.jpeg" />
-      <entry name="?*.jpg" />
-      <entry name="?*.html" />
-      <entry name="?*.dtd" />
-      <entry name="?*.tld" />
-    </wildcardResourcePatterns>
-  </component>
-  <component name="DataSourceManagerImpl" />
-  <component name="DependenciesAnalyzeManager">
-    <option name="myForwardDirection" value="false" />
-  </component>
-  <component name="DependencyValidationManager" />
-  <component name="EclipseCompilerSettings">
-    <option name="DEBUGGING_INFO" value="true" />
-    <option name="GENERATE_NO_WARNINGS" value="true" />
-    <option name="DEPRECATION" value="false" />
-    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
-    <option name="MAXIMUM_HEAP_SIZE" value="128" />
-  </component>
-  <component name="EclipseEmbeddedCompilerSettings">
-    <option name="DEBUGGING_INFO" value="true" />
-    <option name="GENERATE_NO_WARNINGS" value="true" />
-    <option name="DEPRECATION" value="false" />
-    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
-    <option name="MAXIMUM_HEAP_SIZE" value="128" />
-  </component>
-  <component name="EntryPointsManager">
-    <entry_points />
-  </component>
-  <component name="ExportToHTMLSettings">
-    <option name="PRINT_LINE_NUMBERS" value="false" />
-    <option name="OPEN_IN_BROWSER" value="false" />
-    <option name="OUTPUT_DIRECTORY" />
-  </component>
-  <component name="GUI Designer component loader factory" />
-  <component name="IdProvider" IDEtalkID="F6EC4D80E2C03FEF19EDD201903A6DFE" />
-  <component name="InspectionProjectProfileManager">
-    <option name="PROJECT_PROFILE" value="Project Default" />
-    <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
-    <scopes />
-    <profiles>
-      <profile version="1.0" is_locked="false">
-        <option name="myName" value="Project Default" />
-        <option name="myLocal" value="false" />
-        <used_levels>
-          <error>
-            <option name="myName" value="ERROR" />
-            <option name="myVal" value="400" />
-          </error>
-          <warning>
-            <option name="myName" value="WARNING" />
-            <option name="myVal" value="300" />
-          </warning>
-          <information>
-            <option name="myName" value="INFO" />
-            <option name="myVal" value="200" />
-          </information>
-          <server>
-            <option name="myName" value="SERVER PROBLEM" />
-            <option name="myVal" value="100" />
-          </server>
-        </used_levels>
-        <inspection_tool class="ClassReferencesSubclass" level="WARNING" enabled="true" />
-        <inspection_tool class="MissingOverrideAnnotation" level="WARNING" enabled="true" />
-        <inspection_tool class="Finalize" level="WARNING" enabled="true" />
-        <inspection_tool class="UnusedImport" level="WARNING" enabled="true" />
-        <inspection_tool class="StaticInheritance" level="WARNING" enabled="true" />
-        <inspection_tool class="RedundantMethodOverride" level="WARNING" enabled="true" />
-        <inspection_tool class="AbstractMethodCallInConstructor" level="WARNING" enabled="true" />
-        <inspection_tool class="RawUseOfParameterizedType" level="WARNING" enabled="true">
-          <option name="ignoreObjectConstruction" value="true" />
-          <option name="ignoreTypeCasts" value="false" />
-        </inspection_tool>
-        <inspection_tool class="SystemGC" level="WARNING" enabled="true" />
-        <inspection_tool class="ConstantNamingConvention" level="WARNING" enabled="true">
-          <option name="m_regex" value="[A-Z_\d]*" />
-          <option name="m_minLength" value="5" />
-          <option name="m_maxLength" value="32" />
-        </inspection_tool>
-        <inspection_tool class="EnumeratedConstantNamingConvention" level="WARNING" enabled="true">
-          <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
-          <option name="m_minLength" value="5" />
-          <option name="m_maxLength" value="32" />
-        </inspection_tool>
-        <inspection_tool class="DivideByZero" level="WARNING" enabled="true" />
-        <inspection_tool class="CloneCallsConstructors" level="WARNING" enabled="true" />
-        <inspection_tool class="CloneDeclaresCloneNotSupported" level="WARNING" enabled="false" />
-        <inspection_tool class="CloneInNonCloneableClass" level="WARNING" enabled="true" />
-        <inspection_tool class="UtilityClassWithoutPrivateConstructor" level="WARNING" enabled="true">
-          <option name="ignoreClassesWithOnlyMain" value="false" />
-        </inspection_tool>
-        <inspection_tool class="UtilityClassWithPublicConstructor" level="WARNING" enabled="true" />
-        <inspection_tool class="ConditionalExpressionWithIdenticalBranches" level="WARNING" enabled="true" />
-        <inspection_tool class="CanBeFinal" level="WARNING" enabled="false">
-          <option name="REPORT_CLASSES" value="false" />
-          <option name="REPORT_METHODS" value="false" />
-          <option name="REPORT_FIELDS" value="true" />
-        </inspection_tool>
-        <inspection_tool class="ThisEscapedInConstructor" level="WARNING" enabled="true" />
-        <inspection_tool class="NonThreadSafeLazyInitialization" level="WARNING" enabled="true" />
-        <inspection_tool class="FieldMayBeStatic" level="WARNING" enabled="true" />
-        <inspection_tool class="InnerClassMayBeStatic" level="WARNING" enabled="true" />
-        <inspection_tool class="MethodMayBeStatic" level="WARNING" enabled="true">
-          <option name="m_onlyPrivateOrFinal" value="false" />
-          <option name="m_ignoreEmptyMethods" value="true" />
-        </inspection_tool>
-        <inspection_tool class="ComponentRegistrationProblems" level="ERROR" enabled="false">
-          <option name="CHECK_PLUGIN_XML" value="true" />
-          <option name="CHECK_JAVA_CODE" value="true" />
-          <option name="CHECK_ACTIONS" value="true" />
-        </inspection_tool>
-        <inspection_tool class="ComponentNotRegistered" level="WARNING" enabled="false">
-          <option name="CHECK_ACTIONS" value="true" />
-          <option name="IGNORE_NON_PUBLIC" value="true" />
-        </inspection_tool>
-        <inspection_tool class="BusyWait" level="WARNING" enabled="true" />
-        <inspection_tool class="UnconditionalWait" level="WARNING" enabled="true" />
-        <inspection_tool class="WaitNotInLoop" level="WARNING" enabled="true" />
-      </profile>
-    </profiles>
-  </component>
-  <component name="JavacSettings">
-    <option name="DEBUGGING_INFO" value="true" />
-    <option name="GENERATE_NO_WARNINGS" value="false" />
-    <option name="DEPRECATION" value="true" />
-    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
-    <option name="MAXIMUM_HEAP_SIZE" value="128" />
-  </component>
-  <component name="JavadocGenerationManager">
-    <option name="OUTPUT_DIRECTORY" />
-    <option name="OPTION_SCOPE" value="protected" />
-    <option name="OPTION_HIERARCHY" value="true" />
-    <option name="OPTION_NAVIGATOR" value="true" />
-    <option name="OPTION_INDEX" value="true" />
-    <option name="OPTION_SEPARATE_INDEX" value="true" />
-    <option name="OPTION_DOCUMENT_TAG_USE" value="false" />
-    <option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
-    <option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
-    <option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
-    <option name="OPTION_DEPRECATED_LIST" value="true" />
-    <option name="OTHER_OPTIONS" value="" />
-    <option name="HEAP_SIZE" />
-    <option name="LOCALE" />
-    <option name="OPEN_IN_BROWSER" value="true" />
-  </component>
-  <component name="JikesSettings">
-    <option name="JIKES_PATH" value="" />
-    <option name="DEBUGGING_INFO" value="true" />
-    <option name="DEPRECATION" value="true" />
-    <option name="GENERATE_NO_WARNINGS" value="false" />
-    <option name="IS_EMACS_ERRORS_MODE" value="true" />
-    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
-  </component>
-  <component name="LogConsolePreferences">
-    <option name="FILTER_ERRORS" value="false" />
-    <option name="FILTER_WARNINGS" value="false" />
-    <option name="FILTER_INFO" value="true" />
-    <option name="CUSTOM_FILTER" />
-  </component>
-  <component name="ProjectModuleManager">
-    <modules>
-      <module fileurl="file://$PROJECT_DIR$/ACTIVITY_NAME.iml" filepath="$PROJECT_DIR$/ACTIVITY_NAME.iml" />
-    </modules>
-  </component>
-  <component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="1.5" project-jdk-type="JavaSDK">
-    <output url="file://$PROJECT_DIR$/bin" />
-  </component>
-  <component name="ProjectRunConfigurationManager" />
-  <component name="RmicSettings">
-    <option name="IS_EANABLED" value="false" />
-    <option name="DEBUGGING_INFO" value="true" />
-    <option name="GENERATE_NO_WARNINGS" value="false" />
-    <option name="GENERATE_IIOP_STUBS" value="false" />
-    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
-  </component>
-  <component name="StarteamVcsAdapter" />
-  <component name="XSLT-Support.FileAssociationsManager" />
-  <component name="com.intellij.jsf.UserDefinedFacesConfigs">
-    <option name="USER_DEFINED_CONFIGS">
-      <value>
-        <list size="0" />
-      </value>
-    </option>
-  </component>
-  <component name="libraryTable">
-    <library name="android">
-      <CLASSES>
-        <root url="jar://ANDROID_SDK_FOLDER/android.jar!/" />
-      </CLASSES>
-      <JAVADOC>
-        <root url="file://ANDROID_SDK_FOLDER/docs/reference" />
-      </JAVADOC>
-      <SOURCES />
-    </library>
-  </component>
-  <UsedPathMacros />
-</project>
diff --git a/tools/scripts/iws.template b/tools/scripts/iws.template
deleted file mode 100644 (file)
index 67d2053..0000000
+++ /dev/null
@@ -1,470 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4" relativePaths="false">
-  <component name="AntConfiguration">
-    <defaultAnt bundledAnt="true" />
-    <buildFile url="file://$PROJECT_DIR$/build.xml">
-      <additionalClassPath />
-      <antReference projectDefault="true" />
-      <customJdkName value="" />
-      <maximumHeapSize value="128" />
-      <properties />
-    </buildFile>
-  </component>
-  <component name="BookmarkManager" />
-  <component name="ChangeBrowserSettings">
-    <option name="MAIN_SPLITTER_PROPORTION" value="0.3" />
-    <option name="MESSAGES_SPLITTER_PROPORTION" value="0.8" />
-    <option name="USE_DATE_BEFORE_FILTER" value="false" />
-    <option name="USE_DATE_AFTER_FILTER" value="false" />
-    <option name="USE_CHANGE_BEFORE_FILTER" value="false" />
-    <option name="USE_CHANGE_AFTER_FILTER" value="false" />
-    <option name="DATE_BEFORE" value="" />
-    <option name="DATE_AFTER" value="" />
-    <option name="CHANGE_BEFORE" value="" />
-    <option name="CHANGE_AFTER" value="" />
-    <option name="USE_USER_FILTER" value="false" />
-    <option name="USER" value="" />
-  </component>
-  <component name="ChangeListManager">
-    <list default="true" name="Default" comment="" />
-  </component>
-  <component name="ChangeListSynchronizer" />
-  <component name="ChangesViewManager" flattened_view="true" />
-  <component name="CheckinPanelState" />
-  <component name="Commander">
-    <leftPanel />
-    <rightPanel />
-    <splitter proportion="0.5" />
-  </component>
-  <component name="CompilerWorkspaceConfiguration">
-    <option name="COMPILE_IN_BACKGROUND" value="false" />
-    <option name="AUTO_SHOW_ERRORS_IN_EDITOR" value="true" />
-    <option name="CLOSE_MESSAGE_VIEW_IF_SUCCESS" value="true" />
-    <option name="COMPILE_DEPENDENT_FILES" value="false" />
-    <option name="CLEAR_OUTPUT_DIRECTORY" value="false" />
-    <option name="ASSERT_NOT_NULL" value="true" />
-  </component>
-  <component name="CoverageDataManager" />
-  <component name="Cvs2Configuration">
-    <option name="PRUNE_EMPTY_DIRECTORIES" value="true" />
-    <option name="MERGING_MODE" value="0" />
-    <option name="MERGE_WITH_BRANCH1_NAME" value="HEAD" />
-    <option name="MERGE_WITH_BRANCH2_NAME" value="HEAD" />
-    <option name="RESET_STICKY" value="false" />
-    <option name="CREATE_NEW_DIRECTORIES" value="true" />
-    <option name="DEFAULT_TEXT_FILE_SUBSTITUTION" value="kv" />
-    <option name="PROCESS_UNKNOWN_FILES" value="false" />
-    <option name="PROCESS_DELETED_FILES" value="false" />
-    <option name="PROCESS_IGNORED_FILES" value="false" />
-    <option name="RESERVED_EDIT" value="false" />
-    <option name="CHECKOUT_DATE_OR_REVISION_SETTINGS">
-      <value>
-        <option name="BRANCH" value="" />
-        <option name="DATE" value="" />
-        <option name="USE_BRANCH" value="false" />
-        <option name="USE_DATE" value="false" />
-      </value>
-    </option>
-    <option name="UPDATE_DATE_OR_REVISION_SETTINGS">
-      <value>
-        <option name="BRANCH" value="" />
-        <option name="DATE" value="" />
-        <option name="USE_BRANCH" value="false" />
-        <option name="USE_DATE" value="false" />
-      </value>
-    </option>
-    <option name="SHOW_CHANGES_REVISION_SETTINGS">
-      <value>
-        <option name="BRANCH" value="" />
-        <option name="DATE" value="" />
-        <option name="USE_BRANCH" value="false" />
-        <option name="USE_DATE" value="false" />
-      </value>
-    </option>
-    <option name="SHOW_OUTPUT" value="false" />
-    <option name="ADD_WATCH_INDEX" value="0" />
-    <option name="REMOVE_WATCH_INDEX" value="0" />
-    <option name="UPDATE_KEYWORD_SUBSTITUTION" />
-    <option name="MAKE_NEW_FILES_READONLY" value="false" />
-    <option name="SHOW_CORRUPTED_PROJECT_FILES" value="0" />
-    <option name="TAG_AFTER_PROJECT_COMMIT" value="false" />
-    <option name="OVERRIDE_EXISTING_TAG_FOR_PROJECT" value="true" />
-    <option name="TAG_AFTER_PROJECT_COMMIT_NAME" value="" />
-    <option name="CLEAN_COPY" value="false" />
-  </component>
-  <component name="DaemonCodeAnalyzer">
-    <disable_hints />
-  </component>
-  <component name="DebuggerManager">
-    <breakpoint_any>
-      <breakpoint>
-        <option name="NOTIFY_CAUGHT" value="true" />
-        <option name="NOTIFY_UNCAUGHT" value="true" />
-        <option name="ENABLED" value="false" />
-        <option name="SUSPEND_POLICY" value="SuspendAll" />
-        <option name="LOG_ENABLED" value="false" />
-        <option name="LOG_EXPRESSION_ENABLED" value="false" />
-        <option name="COUNT_FILTER_ENABLED" value="false" />
-        <option name="COUNT_FILTER" value="0" />
-        <option name="CONDITION_ENABLED" value="false" />
-        <option name="CLASS_FILTERS_ENABLED" value="false" />
-        <option name="INSTANCE_FILTERS_ENABLED" value="false" />
-        <option name="CONDITION" value="" />
-        <option name="LOG_MESSAGE" value="" />
-      </breakpoint>
-      <breakpoint>
-        <option name="NOTIFY_CAUGHT" value="true" />
-        <option name="NOTIFY_UNCAUGHT" value="true" />
-        <option name="ENABLED" value="false" />
-        <option name="SUSPEND_POLICY" value="SuspendAll" />
-        <option name="LOG_ENABLED" value="false" />
-        <option name="LOG_EXPRESSION_ENABLED" value="false" />
-        <option name="COUNT_FILTER_ENABLED" value="false" />
-        <option name="COUNT_FILTER" value="0" />
-        <option name="CONDITION_ENABLED" value="false" />
-        <option name="CLASS_FILTERS_ENABLED" value="false" />
-        <option name="INSTANCE_FILTERS_ENABLED" value="false" />
-        <option name="CONDITION" value="" />
-        <option name="LOG_MESSAGE" value="" />
-      </breakpoint>
-    </breakpoint_any>
-    <breakpoint_rules />
-    <ui_properties />
-  </component>
-  <component name="ErrorTreeViewConfiguration">
-    <option name="IS_AUTOSCROLL_TO_SOURCE" value="false" />
-    <option name="HIDE_WARNINGS" value="false" />
-  </component>
-  <component name="FavoritesManager">
-    <favorites_list name="LunarLander" />
-  </component>
-  <component name="FavoritesProjectViewPane" />
-       <component name="FileEditorManager">
-    <leaf>
-      <file leaf-file-name="ACTIVITY_NAME.java" pinned="false" current="true" current-in-tab="true">
-        <entry file="file://$PROJECT_DIR$/src/PACKAGE_PATH/ACTIVITY_NAME.java">
-          <provider selected="true" editor-type-id="text-editor">
-            <state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.08211144">
-              <folding />
-            </state>
-          </provider>
-        </entry>
-      </file>
-    </leaf>
-  </component>
-  <component name="FindManager">
-    <FindUsagesManager>
-      <setting name="OPEN_NEW_TAB" value="false" />
-    </FindUsagesManager>
-  </component>
-  <component name="HierarchyBrowserManager">
-    <option name="IS_AUTOSCROLL_TO_SOURCE" value="false" />
-    <option name="SORT_ALPHABETICALLY" value="false" />
-    <option name="HIDE_CLASSES_WHERE_METHOD_NOT_IMPLEMENTED" value="false" />
-  </component>
-  <component name="InspectionManager">
-    <option name="AUTOSCROLL_TO_SOURCE" value="false" />
-    <option name="SPLITTER_PROPORTION" value="0.5" />
-    <option name="GROUP_BY_SEVERITY" value="false" />
-    <option name="FILTER_RESOLVED_ITEMS" value="true" />
-    <option name="ANALYZE_TEST_SOURCES" value="true" />
-    <option name="SHOW_DIFF_WITH_PREVIOUS_RUN" value="false" />
-    <option name="SCOPE_TYPE" value="1" />
-    <option name="CUSTOM_SCOPE_NAME" value="" />
-    <option name="SHOW_ONLY_DIFF" value="false" />
-    <option name="myCurrentProfileName" value="Default" />
-  </component>
-  <component name="J2EEProjectPane" />
-  <component name="JspContextManager" />
-  <component name="ModuleEditorState">
-    <option name="LAST_EDITED_MODULE_NAME" />
-    <option name="LAST_EDITED_TAB_NAME" />
-  </component>
-  <component name="NamedScopeManager" />
-  <component name="PackagesPane">
-    <subPane>
-      <PATH>
-        <PATH_ELEMENT>
-          <option name="myItemId" value="ACTIVITY_NAME.ipr" />
-          <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PackageViewProjectNode" />
-        </PATH_ELEMENT>
-        <PATH_ELEMENT>
-          <option name="myItemId" value="ACTIVITY_NAME" />
-          <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PackageViewModuleNode" />
-        </PATH_ELEMENT>
-      </PATH>
-    </subPane>
-  </component>
-  <component name="PerforceChangeBrowserSettings">
-    <option name="USE_CLIENT_FILTER" value="true" />
-    <option name="CLIENT" value="" />
-  </component>
-  <component name="PerforceDirect.Settings">
-    <option name="useP4CONFIG" value="true" />
-    <option name="port" value="&lt;perforce_server&gt;:1666" />
-    <option name="client" value="" />
-    <option name="user" value="" />
-    <option name="passwd" value="" />
-    <option name="showCmds" value="false" />
-    <option name="useNativeApi" value="false" />
-    <option name="pathToExec" value="p4" />
-    <option name="useCustomPathToExec" value="false" />
-    <option name="SYNC_FORCE" value="false" />
-    <option name="SYNC_RUN_RESOLVE" value="true" />
-    <option name="REVERT_UNCHANGED_FILES" value="true" />
-    <option name="CHARSET" value="none" />
-    <option name="SHOW_BRANCHES_HISTORY" value="true" />
-    <option name="ENABLED" value="true" />
-    <option name="USE_LOGIN" value="false" />
-    <option name="LOGIN_SILENTLY" value="false" />
-    <option name="INTEGRATE_RUN_RESOLVE" value="true" />
-    <option name="INTEGRATE_REVERT_UNCHANGED" value="true" />
-    <option name="SERVER_TIMEOUT" value="20000" />
-  </component>
-  <component name="ProjectLevelVcsManager">
-    <OptionsSetting value="true" id="Add" />
-    <OptionsSetting value="true" id="Remove" />
-    <OptionsSetting value="true" id="Checkin" />
-    <OptionsSetting value="true" id="Checkout" />
-    <OptionsSetting value="true" id="Update" />
-    <OptionsSetting value="true" id="Status" />
-    <OptionsSetting value="true" id="Edit" />
-    <ConfirmationsSetting value="0" id="Add" />
-    <ConfirmationsSetting value="0" id="Remove" />
-  </component>
-  <component name="ProjectPane">
-    <subPane>
-      <PATH>
-        <PATH_ELEMENT>
-          <option name="myItemId" value="ACTIVITY_NAME.ipr" />
-          <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
-        </PATH_ELEMENT>
-        <PATH_ELEMENT>
-          <option name="myItemId" value="ACTIVITY_NAME" />
-          <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewModuleNode" />
-        </PATH_ELEMENT>
-      </PATH>
-    </subPane>
-  </component>
-  <component name="ProjectReloadState">
-    <option name="STATE" value="0" />
-  </component>
-  <component name="ProjectView">
-    <navigator currentView="ProjectPane" proportions="0.1" version="1" splitterProportion="0.5">
-      <flattenPackages />
-      <showMembers />
-      <showModules />
-      <showLibraryContents />
-      <hideEmptyPackages />
-      <abbreviatePackageNames />
-      <showStructure PackagesPane="false" ProjectPane="false" />
-      <autoscrollToSource />
-      <autoscrollFromSource />
-      <sortByType />
-    </navigator>
-  </component>
-  <component name="PropertiesComponent">
-    <property name="MemberChooser.copyJavadoc" value="false" />
-    <property name="GoToClass.includeLibraries" value="false" />
-    <property name="MemberChooser.showClasses" value="true" />
-    <property name="MemberChooser.sorted" value="false" />
-    <property name="GoToFile.includeJavaFiles" value="false" />
-    <property name="GoToClass.toSaveIncludeLibraries" value="false" />
-  </component>
-  <component name="ReadonlyStatusHandler">
-    <option name="SHOW_DIALOG" value="true" />
-  </component>
-  <component name="RecentsManager" />
-  <component name="RestoreUpdateTree" />
-  <component name="RunManager">
-    <configuration default="true" type="Application" factoryName="Application" enabled="false" merge="false">
-      <option name="MAIN_CLASS_NAME" />
-      <option name="VM_PARAMETERS" />
-      <option name="PROGRAM_PARAMETERS" />
-      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
-      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
-      <option name="ALTERNATIVE_JRE_PATH" />
-      <option name="ENABLE_SWING_INSPECTOR" value="false" />
-      <module name="" />
-    </configuration>
-    <configuration default="true" type="Applet" factoryName="Applet">
-      <module name="" />
-      <option name="MAIN_CLASS_NAME" />
-      <option name="HTML_FILE_NAME" />
-      <option name="HTML_USED" value="false" />
-      <option name="WIDTH" value="400" />
-      <option name="HEIGHT" value="300" />
-      <option name="POLICY_FILE" value="/Developer/Applications/IntelliJ IDEA 6.0.4.app/bin/appletviewer.policy" />
-      <option name="VM_PARAMETERS" />
-      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
-      <option name="ALTERNATIVE_JRE_PATH" />
-    </configuration>
-    <configuration default="true" type="JUnit" factoryName="JUnit" enabled="false" merge="false">
-      <module name="" />
-      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
-      <option name="ALTERNATIVE_JRE_PATH" />
-      <option name="PACKAGE_NAME" />
-      <option name="MAIN_CLASS_NAME" />
-      <option name="METHOD_NAME" />
-      <option name="TEST_OBJECT" value="class" />
-      <option name="VM_PARAMETERS" />
-      <option name="PARAMETERS" />
-      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
-      <option name="ADDITIONAL_CLASS_PATH" />
-      <option name="TEST_SEARCH_SCOPE">
-        <value defaultName="wholeProject" />
-      </option>
-    </configuration>
-    <configuration default="true" type="Remote" factoryName="Remote">
-      <option name="USE_SOCKET_TRANSPORT" value="true" />
-      <option name="SERVER_MODE" value="false" />
-      <option name="SHMEM_ADDRESS" value="javadebug" />
-      <option name="HOST" value="localhost" />
-      <option name="PORT" value="5005" />
-    </configuration>
-  </component>
-  <component name="ScopeViewComponent" />
-  <component name="SelectInManager" />
-  <component name="StarteamConfiguration">
-    <option name="SERVER" value="" />
-    <option name="PORT" value="49201" />
-    <option name="USER" value="" />
-    <option name="PASSWORD" value="" />
-    <option name="PROJECT" value="" />
-    <option name="VIEW" value="" />
-    <option name="ALTERNATIVE_WORKING_PATH" value="" />
-    <option name="LOCK_ON_CHECKOUT" value="false" />
-    <option name="UNLOCK_ON_CHECKIN" value="false" />
-  </component>
-  <component name="StructuralSearchPlugin" />
-  <component name="StructureViewFactory">
-    <option name="AUTOSCROLL_MODE" value="true" />
-    <option name="AUTOSCROLL_FROM_SOURCE" value="false" />
-    <option name="ACTIVE_ACTIONS" value="" />
-  </component>
-  <component name="Struts Assistant">
-    <option name="showInputs" value="true" />
-    <option name="resources">
-      <value>
-        <option name="strutsPath" />
-        <option name="strutsHelp" />
-      </value>
-    </option>
-    <option name="selectedTaglibs" />
-    <option name="selectedTaglibs" />
-    <option name="myStrutsValidationEnabled" value="true" />
-    <option name="myTilesValidationEnabled" value="true" />
-    <option name="myValidatorValidationEnabled" value="true" />
-    <option name="myReportErrorsAsWarnings" value="true" />
-  </component>
-  <component name="SvnChangesBrowserSettings">
-    <option name="USE_AUTHOR_FIELD" value="true" />
-    <option name="AUTHOR" value="" />
-    <option name="LOCATION" value="" />
-    <option name="USE_PROJECT_SETTINGS" value="true" />
-    <option name="USE_ALTERNATE_LOCATION" value="false" />
-  </component>
-  <component name="SvnConfiguration">
-    <option name="USER" value="" />
-    <option name="PASSWORD" value="" />
-    <option name="PROCESS_UNRESOLVED" value="false" />
-    <option name="LAST_MERGED_REVISION" />
-    <option name="UPDATE_RUN_STATUS" value="false" />
-    <option name="UPDATE_RECURSIVELY" value="true" />
-    <option name="MERGE_DRY_RUN" value="false" />
-    <upgradeMode>auto</upgradeMode>
-  </component>
-  <component name="TodoView" selected-index="0">
-    <todo-panel id="selected-file">
-      <are-packages-shown value="false" />
-      <are-modules-shown value="false" />
-      <flatten-packages value="false" />
-      <is-autoscroll-to-source value="true" />
-    </todo-panel>
-    <todo-panel id="all">
-      <are-packages-shown value="true" />
-      <are-modules-shown value="false" />
-      <flatten-packages value="false" />
-      <is-autoscroll-to-source value="true" />
-    </todo-panel>
-  </component>
-  <component name="ToolWindowManager">
-    <frame x="0" y="22" width="1440" height="834" extended-state="0" />
-    <editor active="false" />
-    <layout>
-      <window_info id="UI Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="-1" />
-      <window_info id="CVS" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="-1" />
-      <window_info id="IDEtalk" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="-1" />
-      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="7" />
-      <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.24946082" order="0" />
-      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="1" />
-      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" order="1" />
-      <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="-1" />
-      <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" order="6" />
-      <window_info id="Module Dependencies" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="-1" />
-      <window_info id="Dependency Viewer" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="-1" />
-      <window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="-1" />
-      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" order="1" />
-      <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="-1" />
-      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="2" />
-      <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" order="2" />
-      <window_info id="File View" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="-1" />
-      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" order="4" />
-      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" order="0" />
-      <window_info id="IDEtalk Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="-1" />
-      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="-1" />
-      <window_info id="Web" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" order="2" />
-      <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="0" />
-      <window_info id="EJB" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" order="3" />
-      <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" order="5" />
-    </layout>
-  </component>
-  <component name="VCS.FileViewConfiguration">
-    <option name="SELECTED_STATUSES" value="DEFAULT" />
-    <option name="SELECTED_COLUMNS" value="DEFAULT" />
-    <option name="SHOW_FILTERS" value="true" />
-    <option name="CUSTOMIZE_VIEW" value="true" />
-    <option name="SHOW_FILE_HISTORY_AS_TREE" value="true" />
-  </component>
-  <component name="VcsManagerConfiguration">
-    <option name="OFFER_MOVE_TO_ANOTHER_CHANGELIST_ON_PARTIAL_COMMIT" value="true" />
-    <option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="true" />
-    <option name="PERFORM_UPDATE_IN_BACKGROUND" value="false" />
-    <option name="PERFORM_COMMIT_IN_BACKGROUND" value="false" />
-    <option name="PUT_FOCUS_INTO_COMMENT" value="false" />
-    <option name="FORCE_NON_EMPTY_COMMENT" value="false" />
-    <option name="LAST_COMMIT_MESSAGE" />
-    <option name="SAVE_LAST_COMMIT_MESSAGE" value="true" />
-    <option name="CHECKIN_DIALOG_SPLITTER_PROPORTION" value="0.8" />
-    <option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="false" />
-    <option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="false" />
-    <option name="REFORMAT_BEFORE_FILE_COMMIT" value="false" />
-    <option name="FILE_HISTORY_DIALOG_COMMENTS_SPLITTER_PROPORTION" value="0.8" />
-    <option name="FILE_HISTORY_DIALOG_SPLITTER_PROPORTION" value="0.5" />
-    <option name="ERROR_OCCURED" value="false" />
-    <option name="ACTIVE_VCS_NAME" value="CVS" />
-    <option name="UPDATE_GROUP_BY_PACKAGES" value="false" />
-    <option name="SHOW_FILE_HISTORY_AS_TREE" value="false" />
-    <option name="FILE_HISTORY_SPLITTER_PROPORTION" value="0.6" />
-  </component>
-  <component name="XPathView.XPathProjectComponent">
-    <history />
-    <find-history />
-  </component>
-  <component name="XSLT-Support.FileAssociationsSettings" />
-  <component name="antWorkspaceConfiguration">
-    <option name="IS_AUTOSCROLL_TO_SOURCE" value="false" />
-    <option name="FILTER_TARGETS" value="false" />
-  </component>
-  <component name="com.intellij.ide.util.scopeChooser.ScopeChooserConfigurable" proportions="" version="1">
-    <option name="myLastEditedConfigurable" />
-  </component>
-  <component name="com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectRootMasterDetailsConfigurable" proportions="0.1" version="1">
-    <option name="myPlainMode" value="false" />
-    <option name="myLastEditedConfigurable" value="android" />
-  </component>
-  <component name="com.intellij.profile.ui.ErrorOptionsConfigurable" proportions="" version="1">
-    <option name="myLastEditedConfigurable" />
-  </component>
-  <component name="editorHistoryManager" />
-</project>
\ No newline at end of file
index aeb541f..19714a8 100644 (file)
@@ -3,7 +3,7 @@ package PACKAGE;
 import android.app.Activity;
 import android.os.Bundle;
 
-public class ACTIVITY_NAME extends Activity
+public class ACTIVITY_CLASS_NAME extends Activity
 {
     /** Called when the activity is first created. */
     @Override
index c6fa873..08d6f9b 100644 (file)
@@ -9,13 +9,13 @@ import android.test.ActivityInstrumentationTestCase2;
  * <p/>
  * To run this test, you can type:
  * adb shell am instrument -w \
- * -e class PACKAGE.ACTIVITY_NAMETest \
+ * -e class ACTIVITY_FQ_NAME \
  * PACKAGE.tests/android.test.InstrumentationTestRunner
  */
-public class ACTIVITY_NAMETest extends ActivityInstrumentationTestCase2<ACTIVITY_NAME> {
+public class ACTIVITY_CLASS_NAME extends ActivityInstrumentationTestCase2<ACTIVITY_TESTED_CLASS_NAME> {
 
-    public ACTIVITY_NAMETest() {
-        super("PACKAGE", ACTIVITY_NAME.class);
+    public ACTIVITY_CLASS_NAME() {
+        super("PACKAGE", ACTIVITY_TESTED_CLASS_NAME.class);
     }
 
 }
\ No newline at end of file
index 5da5645..2e21f7b 100644 (file)
@@ -460,7 +460,7 @@ class CommandLineProcessor {
             stdout("\nValid actions are composed of a verb and an optional direct object:");
             for (String[] action : mActions) {
 
-                stdout("- %1$6s %2$-7s: %3$s",
+                stdout("- %1$6s %2$-12s: %3$s",
                         action[ACTION_VERB_INDEX],
                         action[ACTION_OBJECT_INDEX],
                         action[ACTION_DESC_INDEX]);
index fa2870d..c691af7 100644 (file)
@@ -28,17 +28,27 @@ import com.android.sdklib.internal.avd.HardwareProperties;
 import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
 import com.android.sdklib.internal.avd.HardwareProperties.HardwareProperty;
 import com.android.sdklib.internal.project.ProjectCreator;
+import com.android.sdklib.internal.project.ProjectProperties;
 import com.android.sdklib.internal.project.ProjectCreator.OutputLevel;
+import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
+import com.android.sdklib.xml.AndroidXPathFactory;
 import com.android.sdkmanager.internal.repository.AboutPage;
 import com.android.sdkmanager.internal.repository.SettingsPage;
 import com.android.sdkuilib.repository.UpdaterWindow;
 
+import org.xml.sax.InputSource;
+
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpressionException;
+
 /**
  * Main class for the 'android' application.
  */
@@ -221,6 +231,10 @@ public class Main {
                 SdkCommandLine.OBJECT_PROJECT.equals(directObject)) {
             createProject();
 
+        } else if (SdkCommandLine.VERB_CREATE.equals(verb) &&
+                SdkCommandLine.OBJECT_TEST_PROJECT.equals(directObject)) {
+            createTestProject();
+
         } else if (SdkCommandLine.VERB_UPDATE.equals(verb) &&
                 SdkCommandLine.OBJECT_PROJECT.equals(directObject)) {
             updateProject();
@@ -314,9 +328,112 @@ public class Main {
                 packageName,
                 activityName,
                 target,
-                false /* isTestProject*/);
+                null /*pathToMain*/);
+    }
+
+    /**
+     * Creates a new Android test project based on command-line parameters
+     */
+    private void createTestProject() {
+
+        String projectDir = getProjectLocation(mSdkCommandLine.getParamLocationPath());
+
+        // first check the path of the parent project, and make sure it's valid.
+        String pathToMainProject = mSdkCommandLine.getParamTestProjectMain();
+
+        File parentProject = new File(pathToMainProject);
+        if (parentProject.isAbsolute() == false) {
+            // if the path is not absolute, we need to resolve it based on the
+            // destination path of the project
+            parentProject = new File(projectDir, pathToMainProject);
+        }
+
+        if (parentProject.isDirectory() == false) {
+            errorAndExit("Main project's directory does not exist: %1$s",
+                    pathToMainProject);
+        }
+
+        // now look for a manifest in there
+        File manifest = new File(parentProject, SdkConstants.FN_ANDROID_MANIFEST_XML);
+        if (manifest.isFile() == false) {
+            errorAndExit("No AndroidManifest.xml file found in the main project directory: %1$s",
+                    parentProject.getAbsolutePath());
+        }
+
+        // now query the manifest for the package file.
+        XPath xpath = AndroidXPathFactory.newXPath();
+        String packageName, activityName;
+
+        try {
+            packageName = xpath.evaluate("/manifest/@package",
+                    new InputSource(new FileInputStream(manifest)));
+
+            mSdkLog.printf("Found main project package: %1$s\n", packageName);
+
+            // now get the name of the first activity we find
+            activityName = xpath.evaluate("/manifest/application/activity[1]/@android:name",
+                    new InputSource(new FileInputStream(manifest)));
+            // xpath will return empty string when there's no match
+            if (activityName == null || activityName.length() == 0) {
+                activityName = null;
+            } else {
+                mSdkLog.printf("Found main project activity: %1$s\n", activityName);
+            }
+        } catch (FileNotFoundException e) {
+            // this shouldn't happen as we test it above.
+            errorAndExit("No AndroidManifest.xml file found in main project.");
+            return; // this is not strictly needed because errorAndExit will stop the execution,
+            // but this makes the java compiler happy, wrt to uninitialized variables.
+        } catch (XPathExpressionException e) {
+            // looks like the main manifest is not valid.
+            errorAndExit("Unable to parse main project manifest to get information.");
+            return; // this is not strictly needed because errorAndExit will stop the execution,
+                    // but this makes the java compiler happy, wrt to uninitialized variables.
+        }
+
+        // now get the target hash
+        ProjectProperties p = ProjectProperties.load(parentProject.getAbsolutePath(),
+                PropertyType.DEFAULT);
+        String targetHash = p.getProperty(ProjectProperties.PROPERTY_TARGET);
+        if (targetHash == null) {
+            errorAndExit("Couldn't find the main project target");
+        }
+
+        // and resolve it.
+        IAndroidTarget target = mSdkManager.getTargetFromHashString(targetHash);
+        if (target == null) {
+            errorAndExit(
+                    "Unable to resolve main project target '%1$s'. You may want to install the platform in your SDK.",
+                    targetHash);
+        }
+
+        mSdkLog.printf("Found main project target: %1$s\n", target.getFullName());
+
+        ProjectCreator creator = new ProjectCreator(mOsSdkFolder,
+                mSdkCommandLine.isVerbose() ? OutputLevel.VERBOSE :
+                    mSdkCommandLine.isSilent() ? OutputLevel.SILENT :
+                        OutputLevel.NORMAL,
+                mSdkLog);
+
+        String projectName = mSdkCommandLine.getParamName();
+
+        if (projectName != null &&
+                !ProjectCreator.RE_PROJECT_NAME.matcher(projectName).matches()) {
+            errorAndExit(
+                "Project name '%1$s' contains invalid characters.\nAllowed characters are: %2$s",
+                projectName, ProjectCreator.CHARS_PROJECT_NAME);
+            return;
+        }
+
+        creator.createProject(projectDir,
+                projectName,
+                packageName,
+                activityName,
+                target,
+                pathToMainProject);
     }
 
+
     /**
      * Updates an existing Android project based on command-line parameters
      */
index a23a65c..35bbd0d 100644 (file)
@@ -31,28 +31,30 @@ class SdkCommandLine extends CommandLineProcessor {
     public final static String VERB_DELETE = "delete";
     public final static String VERB_UPDATE = "update";
 
-    public static final String OBJECT_AVD      = "avd";
-    public static final String OBJECT_AVDS     = "avds";
-    public static final String OBJECT_TARGET   = "target";
-    public static final String OBJECT_TARGETS  = "targets";
-    public static final String OBJECT_PROJECT  = "project";
-    public static final String OBJECT_ADB      = "adb";
-
-    public static final String ARG_ALIAS       = "alias";
-    public static final String ARG_ACTIVITY    = "activity";
-
-    public static final String KEY_ACTIVITY    = ARG_ACTIVITY;
-    public static final String KEY_PACKAGE     = "package";
-    public static final String KEY_MODE        = "mode";
-    public static final String KEY_TARGET_ID   = OBJECT_TARGET;
-    public static final String KEY_NAME        = "name";
-    public static final String KEY_PATH        = "path";
-    public static final String KEY_FILTER      = "filter";
-    public static final String KEY_SKIN        = "skin";
-    public static final String KEY_SDCARD      = "sdcard";
-    public static final String KEY_FORCE       = "force";
-    public static final String KEY_RENAME      = "rename";
-    public static final String KEY_SUBPROJECTS = "subprojects";
+    public static final String OBJECT_AVD          = "avd";
+    public static final String OBJECT_AVDS         = "avds";
+    public static final String OBJECT_TARGET       = "target";
+    public static final String OBJECT_TARGETS      = "targets";
+    public static final String OBJECT_PROJECT      = "project";
+    public static final String OBJECT_TEST_PROJECT = "test-project";
+    public static final String OBJECT_ADB          = "adb";
+
+    public static final String ARG_ALIAS        = "alias";
+    public static final String ARG_ACTIVITY     = "activity";
+
+    public static final String KEY_ACTIVITY     = ARG_ACTIVITY;
+    public static final String KEY_PACKAGE      = "package";
+    public static final String KEY_MODE         = "mode";
+    public static final String KEY_TARGET_ID    = OBJECT_TARGET;
+    public static final String KEY_NAME         = "name";
+    public static final String KEY_PATH         = "path";
+    public static final String KEY_FILTER       = "filter";
+    public static final String KEY_SKIN         = "skin";
+    public static final String KEY_SDCARD       = "sdcard";
+    public static final String KEY_FORCE        = "force";
+    public static final String KEY_RENAME       = "rename";
+    public static final String KEY_SUBPROJECTS  = "subprojects";
+    public static final String KEY_MAIN_PROJECT = "main";
 
     /**
      * Action definitions for SdkManager command line.
@@ -89,6 +91,11 @@ class SdkCommandLine extends CommandLineProcessor {
             { VERB_UPDATE, OBJECT_PROJECT,
                 "Updates an Android Project (must have an AndroidManifest.xml)." },
 
+            { VERB_CREATE, OBJECT_TEST_PROJECT,
+                "Creates a new Android Test Project." },
+            { VERB_UPDATE, OBJECT_TEST_PROJECT,
+                "Updates an Android Test Project (must have an AndroidManifest.xml)." },
+
             { VERB_UPDATE, OBJECT_ADB,
                 "Updates adb to support the USB devices declared in the SDK add-ons." },
         };
@@ -167,6 +174,18 @@ class SdkCommandLine extends CommandLineProcessor {
                 VERB_CREATE, OBJECT_PROJECT, "n", KEY_NAME,
                 "Project name", null);
 
+        // --- create test-project ---
+        define(Mode.STRING, true,
+                VERB_CREATE, OBJECT_TEST_PROJECT,
+                "p", KEY_PATH,
+                "Location path of new project", null);
+        define(Mode.STRING, false,
+                VERB_CREATE, OBJECT_TEST_PROJECT, "n", KEY_NAME,
+                "Project name", null);
+        define(Mode.STRING, true,
+                VERB_CREATE, OBJECT_TEST_PROJECT, "m", KEY_MAIN_PROJECT,
+                "Location path of the project to test, relative to the new project", null);
+
         // --- update project ---
 
         define(Mode.STRING, true,
@@ -185,6 +204,17 @@ class SdkCommandLine extends CommandLineProcessor {
                 VERB_UPDATE, OBJECT_PROJECT,
                 "s", KEY_SUBPROJECTS,
                 "Also update any projects in sub-folders, such as test projects.", false);
+
+        // --- update test project ---
+
+        define(Mode.STRING, true,
+                VERB_UPDATE, OBJECT_TEST_PROJECT,
+                "p", KEY_PATH,
+                "Location path of the project", null);
+        define(Mode.STRING, true,
+                VERB_UPDATE, OBJECT_TEST_PROJECT,
+                "m", KEY_MAIN_PROJECT,
+                "Location path of the project to test", null);
     }
 
     @Override
@@ -255,4 +285,11 @@ class SdkCommandLine extends CommandLineProcessor {
     public boolean getParamSubProject() {
         return ((Boolean) getValue(null, OBJECT_PROJECT, KEY_SUBPROJECTS)).booleanValue();
     }
+
+    // -- some helpers for test-project action flags
+
+    /** Helper to retrieve the --main value. */
+    public String getParamTestProjectMain() {
+        return ((String) getValue(null, OBJECT_TEST_PROJECT, KEY_MAIN_PROJECT));
+    }
 }
index 4ef3468..b276ae3 100644 (file)
@@ -78,6 +78,8 @@ public final class SdkConstants {
     public final static String FN_PLUGIN_PROP = "plugin.prop";
     /** add-on manifest file */
     public final static String FN_MANIFEST_INI = "manifest.ini";
+    /** add-on layout device XML file. */
+    public final static String FN_DEVICES_XML = "devices.xml";
     /** hardware properties definition file */
     public final static String FN_HARDWARE_INI = "hardware-properties.ini";
 
index 3e15e15..c4ab013 100644 (file)
@@ -20,6 +20,7 @@ import com.android.sdklib.IAndroidTarget;
 import com.android.sdklib.ISdkLog;
 import com.android.sdklib.SdkConstants;
 import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
+import com.android.sdklib.xml.AndroidManifest;
 
 import org.w3c.dom.NodeList;
 import org.xml.sax.InputSource;
@@ -44,8 +45,7 @@ import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
 
 /**
- * Creates the basic files needed to get an Android project up and running. Also
- * allows creation of IntelliJ project files.
+ * Creates the basic files needed to get an Android project up and running.
  *
  * @hide
  */
@@ -55,13 +55,22 @@ public class ProjectCreator {
     private final static String PH_JAVA_FOLDER = "PACKAGE_PATH";
     /** Package name substitution string used in template files, i.e. "PACKAGE" */
     private final static String PH_PACKAGE = "PACKAGE";
-    /** Activity name substitution string used in template files, i.e. "ACTIVITY_NAME". */
+    /** Activity name substitution string used in template files, i.e. "ACTIVITY_NAME".
+     * @deprecated This is only used for older templates. For new ones see
+     * {@link #PH_ACTIVITY_ENTRY_NAME}, and {@link #PH_ACTIVITY_CLASS_NAME}. */
     private final static String PH_ACTIVITY_NAME = "ACTIVITY_NAME";
+    /** Activity name substitution string used in manifest templates, i.e. "ACTIVITY_ENTRY_NAME".*/
+    private final static String PH_ACTIVITY_ENTRY_NAME = "ACTIVITY_ENTRY_NAME";
+    /** Activity name substitution string used in class templates, i.e. "ACTIVITY_CLASS_NAME".*/
+    private final static String PH_ACTIVITY_CLASS_NAME = "ACTIVITY_CLASS_NAME";
+    /** Activity FQ-name substitution string used in class templates, i.e. "ACTIVITY_FQ_NAME".*/
+    private final static String PH_ACTIVITY_FQ_NAME = "ACTIVITY_FQ_NAME";
+    /** Original Activity class name substitution string used in class templates, i.e.
+     * "ACTIVITY_TESTED_CLASS_NAME".*/
+    private final static String PH_ACTIVITY_TESTED_CLASS_NAME = "ACTIVITY_TESTED_CLASS_NAME";
     /** Project name substitution string used in template files, i.e. "PROJECT_NAME". */
     private final static String PH_PROJECT_NAME = "PROJECT_NAME";
 
-    private final static String FOLDER_TESTS = "tests";
-
     /** Pattern for characters accepted in a project name. Since this will be used as a
      * directory name, we're being a bit conservative on purpose: dot and space cannot be used. */
     public static final Pattern RE_PROJECT_NAME = Pattern.compile("[a-zA-Z0-9_]+");
@@ -135,17 +144,16 @@ public class ProjectCreator {
      *          {@link #RE_PROJECT_NAME} regex.
      * @param packageName the package of the project. The name must match the
      *          {@link #RE_PACKAGE_NAME} regex.
-     * @param activityName the activity of the project as it will appear in the manifest. Can be
+     * @param activityEntry the activity of the project as it will appear in the manifest. Can be
      *          null if no activity should be created. The name must match the
      *          {@link #RE_ACTIVITY_NAME} regex.
      * @param target the project target.
-     * @param isTestProject whether the project to create is a test project. Caller should
-     *        initially call this will false. The method will call itself back to create
-     *        a test project as needed.
+     * @param pathToMainProject if non-null the project will be setup to test a main project
+     * located at the given path.
      */
     public void createProject(String folderPath, String projectName,
-            String packageName, String activityName, IAndroidTarget target,
-            boolean isTestProject) {
+            String packageName, String activityEntry, IAndroidTarget target,
+            String pathToMainProject) {
 
         // create project folder if it does not exist
         File projectFolder = new File(folderPath);
@@ -185,6 +193,8 @@ public class ProjectCreator {
         }
 
         try {
+            boolean isTestProject = pathToMainProject != null;
+
             // first create the project properties.
 
             // location of the SDK goes in localProperty
@@ -202,9 +212,16 @@ public class ProjectCreator {
             // create a build.properties file with just the application package
             ProjectProperties buildProperties = ProjectProperties.create(folderPath,
                     PropertyType.BUILD);
-            buildProperties.setProperty(ProjectProperties.PROPERTY_APP_PACKAGE, packageName);
-            if (isTestProject == true) {
-                buildProperties.setProperty(ProjectProperties.PROPERTY_TESTED_PROJECT, "..");
+
+            // only put application.package for older target where the rules file didn't.
+            // grab it through xpath
+            if (target.getVersion().getApiLevel() < 4) {
+                buildProperties.setProperty(ProjectProperties.PROPERTY_APP_PACKAGE, packageName);
+            }
+
+            if (isTestProject) {
+                buildProperties.setProperty(ProjectProperties.PROPERTY_TESTED_PROJECT,
+                        pathToMainProject);
             }
 
             buildProperties.save();
@@ -221,19 +238,76 @@ public class ProjectCreator {
             // put this path in the place-holder map for project files that needs to list
             // files manually.
             keywords.put(PH_JAVA_FOLDER, packagePath);
-
             keywords.put(PH_PACKAGE, packageName);
-            if (activityName != null) {
-                keywords.put(PH_ACTIVITY_NAME, activityName);
+
+
+            // compute some activity related information
+            String fqActivityName = null, activityPath = null, activityClassName = null;
+            String originalActivityEntry = activityEntry;
+            String originalActivityClassName = null;
+            if (activityEntry != null) {
+                if (isTestProject) {
+                    // append Test so that it doesn't collide with the main project activity.
+                    activityEntry += "Test";
+
+                    // get the classname from the original activity entry.
+                    int pos = originalActivityEntry.lastIndexOf('.');
+                    if (pos != -1) {
+                        originalActivityClassName = originalActivityEntry.substring(pos + 1);
+                    } else {
+                        originalActivityClassName = originalActivityEntry;
+                    }
+                }
+
+                // get the fully qualified name of the activity
+                fqActivityName = AndroidManifest.combinePackageAndClassName(packageName,
+                        activityEntry);
+
+                // get the activity path (replace the . to /)
+                activityPath = stripString(fqActivityName.replace(".", File.separator),
+                        File.separatorChar);
+
+                // remove the last segment, so that we only have the path to the activity, but
+                // not the activity filename itself.
+                activityPath = activityPath.substring(0,
+                        activityPath.lastIndexOf(File.separatorChar));
+
+                // finally, get the class name for the activity
+                activityClassName = fqActivityName.substring(fqActivityName.lastIndexOf('.') + 1);
+            }
+
+            // at this point we have the following for the activity:
+            // activityEntry: this is the manifest entry. For instance .MyActivity
+            // fqActivityName: full-qualified class name: com.foo.MyActivity
+            // activityClassName: only the classname: MyActivity
+            // originalActivityClassName: the classname of the activity being tested (if applicable)
+
+            // Add whatever activity info is needed in the place-holder map.
+            // Older templates only expect ACTIVITY_NAME to be the same (and unmodified for tests).
+            if (target.getVersion().getApiLevel() < 4) { // legacy
+                if (originalActivityEntry != null) {
+                    keywords.put(PH_ACTIVITY_NAME, originalActivityEntry);
+                }
+            } else {
+                // newer templates make a difference between the manifest entries, classnames,
+                // as well as the main and test classes.
+                if (activityEntry != null) {
+                    keywords.put(PH_ACTIVITY_ENTRY_NAME, activityEntry);
+                    keywords.put(PH_ACTIVITY_CLASS_NAME, activityClassName);
+                    keywords.put(PH_ACTIVITY_FQ_NAME, fqActivityName);
+                    if (originalActivityClassName != null) {
+                        keywords.put(PH_ACTIVITY_TESTED_CLASS_NAME, originalActivityClassName);
+                    }
+                }
             }
 
             // Take the project name from the command line if there's one
             if (projectName != null) {
                 keywords.put(PH_PROJECT_NAME, projectName);
             } else {
-                if (activityName != null) {
-                    // Use the activity as project name
-                    keywords.put(PH_PROJECT_NAME, activityName);
+                if (activityClassName != null) {
+                    // Use the activity class name as project name
+                    keywords.put(PH_PROJECT_NAME, activityClassName);
                 } else {
                     // We need a project name. Just pick up the basename of the project
                     // directory.
@@ -242,21 +316,21 @@ public class ProjectCreator {
                 }
             }
 
-            // create the source folder and the java package folders.
-            String srcFolderPath = SdkConstants.FD_SOURCES + File.separator + packagePath;
-            File sourceFolder = createDirs(projectFolder, srcFolderPath);
-            String javaTemplate = "java_file.template";
-            String activityFileName = activityName + ".java";
-            if (isTestProject) {
-                javaTemplate = "java_tests_file.template";
-                activityFileName = activityName + "Test.java";
-            }
-            installTemplate(javaTemplate, new File(sourceFolder, activityFileName),
-                    keywords, target);
+            // create the source folder for the activity
+            if (activityClassName != null) {
+                String srcActivityFolderPath = SdkConstants.FD_SOURCES + File.separator + activityPath;
+                File sourceFolder = createDirs(projectFolder, srcActivityFolderPath);
 
-            // create the generate source folder
-            srcFolderPath = SdkConstants.FD_GEN_SOURCES + File.separator + packagePath;
-            sourceFolder = createDirs(projectFolder, srcFolderPath);
+                String javaTemplate = isTestProject ? "java_tests_file.template"
+                        : "java_file.template";
+                String activityFileName = activityClassName + ".java";
+
+                installTemplate(javaTemplate, new File(sourceFolder, activityFileName),
+                        keywords, target);
+            } else {
+                // we should at least create 'src'
+                createDirs(projectFolder, SdkConstants.FD_SOURCES);
+            }
 
             // create other useful folders
             File resourceFodler = createDirs(projectFolder, SdkConstants.FD_RESOURCES);
@@ -287,16 +361,6 @@ public class ProjectCreator {
             installTemplate("build.template",
                     new File(projectFolder, SdkConstants.FN_BUILD_XML),
                     keywords);
-
-            // if this is not a test project, then we create one.
-            if (isTestProject == false) {
-                // create the test project folder.
-                createDirs(projectFolder, FOLDER_TESTS);
-                File testProjectFolder = new File(folderPath, FOLDER_TESTS);
-
-                createProject(testProjectFolder.getAbsolutePath(), projectName, packageName,
-                        activityName, target, true /*isTestProject*/);
-            }
         } catch (ProjectCreateException e) {
             mLog.error(e, null);
         } catch (IOException e) {
index 694e285..6e29e5a 100644 (file)
@@ -251,8 +251,10 @@ public final class ProjectProperties {
                 writer.write(comment);
             }
             String value = entry.getValue();
-            value = value.replaceAll("\\\\", "\\\\\\\\");
-            writer.write(String.format("%s=%s\n", entry.getKey(), value));
+            if (value != null) {
+                value = value.replaceAll("\\\\", "\\\\\\\\");
+                writer.write(String.format("%s=%s\n", entry.getKey(), value));
+            }
         }
 
         // close the file to flush
 package com.android.sdklib.xml;
 
 /**
- * Constants for nodes and attributes of the AndroidManifest.xml file.
+ * Helper and Constants for the AndroidManifest.xml file.
  *
  */
-public final class ManifestConstants {
+public final class AndroidManifest {
 
     public final static String NODE_MANIFEST = "manifest"; //$NON-NLS-1$
     public final static String NODE_APPLICATION = "application"; //$NON-NLS-1$
@@ -42,4 +42,39 @@ public final class ManifestConstants {
     public final static String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion"; //$NON-NLS-$
     public final static String ATTRIBUTE_TARGET_PACKAGE = "targetPackage"; //$NON-NLS-1$
     public final static String ATTRIBUTE_EXPORTED = "exported"; //$NON-NLS-1$
+
+
+    /**
+     * Combines a java package, with a class value from the manifest to make a fully qualified
+     * class name
+     * @param javaPackage the java package from the manifest.
+     * @param className the class name from the manifest.
+     * @return the fully qualified class name.
+     */
+    public static String combinePackageAndClassName(String javaPackage, String className) {
+        if (className == null || className.length() == 0) {
+            return javaPackage;
+        }
+        if (javaPackage == null || javaPackage.length() == 0) {
+            return className;
+        }
+
+        // the class name can be a subpackage (starts with a '.'
+        // char), a simple class name (no dot), or a full java package
+        boolean startWithDot = (className.charAt(0) == '.');
+        boolean hasDot = (className.indexOf('.') != -1);
+        if (startWithDot || hasDot == false) {
+
+            // add the concatenation of the package and class name
+            if (startWithDot) {
+                return javaPackage + className;
+            } else {
+                return javaPackage + '.' + className;
+            }
+        } else {
+            // just add the class as it should be a fully qualified java name.
+            return className;
+        }
+    }
+
 }
index fc34aeb..641cd81 100644 (file)
@@ -18,7 +18,9 @@ package com.android.sdklib.xml;
 
 import com.android.sdklib.SdkConstants;
 
+import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 
 import javax.xml.XMLConstants;
 import javax.xml.namespace.NamespaceContext;
@@ -39,7 +41,8 @@ public class AndroidXPathFactory {
         private final static AndroidNamespaceContext sThis = new AndroidNamespaceContext(
                 DEFAULT_NS_PREFIX);
 
-        private String mAndroidPrefix;
+        private final String mAndroidPrefix;
+        private final List<String> mAndroidPrefixes = new ArrayList<String>();
 
         /**
          * Returns the default {@link AndroidNamespaceContext}.
@@ -54,6 +57,7 @@ public class AndroidXPathFactory {
          */
         public AndroidNamespaceContext(String androidPrefix) {
             mAndroidPrefix = androidPrefix;
+            mAndroidPrefixes.add(mAndroidPrefix);
         }
 
         public String getNamespaceURI(String prefix) {
@@ -67,14 +71,18 @@ public class AndroidXPathFactory {
         }
 
         public String getPrefix(String namespaceURI) {
-            // This isn't necessary for our use.
-            assert false;
+            if (SdkConstants.NS_RESOURCES.equals(namespaceURI)) {
+                return mAndroidPrefix;
+            }
+
             return null;
         }
 
         public Iterator<?> getPrefixes(String namespaceURI) {
-            // This isn't necessary for our use.
-            assert false;
+            if (SdkConstants.NS_RESOURCES.equals(namespaceURI)) {
+                return mAndroidPrefixes.iterator();
+            }
+
             return null;
         }
     }