OSDN Git Service

Refactor IM client to build all stuff in a single APK
authorScott Su <scott.su@myriadgroup.com>
Thu, 20 Aug 2009 14:13:20 +0000 (22:13 +0800)
committerWei Huang <weih@google.com>
Sat, 22 Aug 2009 18:24:42 +0000 (11:24 -0700)
- IM app was separated as three separated parts before: IM.apk, com.android.im.plugin.jar and the plugin APK. With this structure, it's hard to maintain the dependency and impossible to update through Market.
- The plug-in structure is kept with some changes: instead of with aidl files in a shared library, they are changed as normal java interfaces and will be built in the apk now.
- The branding resources have to be put in IM/res now since there is only one APK after the refactoring.
- The landing page has been moved to IM APK from ImProvider since GTalk has been separated from IMPS client.

88 files changed:
Android.mk
AndroidManifest.xml
libwbxml/Android.mk
libwbxml/include/imps_encoder.h
libwbxml/include/wbxml_encoder.h
libwbxml/src/imps_encoder.cpp
libwbxml/src/wbxml_encoder.cpp [new file with mode: 0644]
plugin/Android.mk [deleted file]
plugin/com/android/im/plugin/ImPlugin.java [moved from plugin/com/android/im/plugin/IImPlugin.aidl with 91% similarity]
plugin/com/android/im/plugin/PasswordDigest.java [moved from plugin/com/android/im/plugin/IPasswordDigest.aidl with 86% similarity]
plugin/com/android/im/plugin/PresenceMapping.java [moved from plugin/com/android/im/plugin/IPresenceMapping.aidl with 95% similarity]
res/color/landing_page_text.xml [new file with mode: 0644]
res/color/landing_page_text_secondary.xml [new file with mode: 0644]
res/drawable/default_background.9.png [moved from samples/PluginDemo/res/drawable/emo_im_cool.png with 75% similarity]
res/layout/account_view.xml [new file with mode: 0644]
res/layout/contact_list_view.xml
res/layout/contact_view.xml
res/layout/group_view.xml
res/values/strings.xml
samples/PluginDemo/Android.mk [deleted file]
samples/PluginDemo/AndroidManifest.xml [deleted file]
samples/PluginDemo/res/drawable/chat.png [deleted file]
samples/PluginDemo/res/drawable/chat_new.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_angel.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_crying.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_embarrassed.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_foot_in_mouth.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_happy.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_kissing.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_laughing.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_lips_are_sealed.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_money_mouth.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_sad.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_surprised.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_tongue_sticking_out.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_undecided.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_winking.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_wtf.png [deleted file]
samples/PluginDemo/res/drawable/emo_im_yelling.png [deleted file]
samples/PluginDemo/res/drawable/im_logo.png [deleted file]
samples/PluginDemo/res/drawable/im_logo_splashscr.png [deleted file]
samples/PluginDemo/res/values-cs/strings.xml [deleted file]
samples/PluginDemo/res/values-da/strings.xml [deleted file]
samples/PluginDemo/res/values-de/strings.xml [deleted file]
samples/PluginDemo/res/values-el/strings.xml [deleted file]
samples/PluginDemo/res/values-es-rUS/strings.xml [deleted file]
samples/PluginDemo/res/values-es/strings.xml [deleted file]
samples/PluginDemo/res/values-fr/strings.xml [deleted file]
samples/PluginDemo/res/values-it/strings.xml [deleted file]
samples/PluginDemo/res/values-ja/strings.xml [deleted file]
samples/PluginDemo/res/values-ko/strings.xml [deleted file]
samples/PluginDemo/res/values-nb/strings.xml [deleted file]
samples/PluginDemo/res/values-nl/strings.xml [deleted file]
samples/PluginDemo/res/values-pl/strings.xml [deleted file]
samples/PluginDemo/res/values-pt-rPT/strings.xml [deleted file]
samples/PluginDemo/res/values-pt/strings.xml [deleted file]
samples/PluginDemo/res/values-ru/strings.xml [deleted file]
samples/PluginDemo/res/values-sv/strings.xml [deleted file]
samples/PluginDemo/res/values-tr/strings.xml [deleted file]
samples/PluginDemo/res/values-zh-rCN/strings.xml [deleted file]
samples/PluginDemo/res/values-zh-rTW/strings.xml [deleted file]
samples/PluginDemo/res/values/strings.xml [deleted file]
samples/PluginDemo/src/com/android/im/plugin/demo/DemoImPlugin.java
samples/PluginDemo/src/com/android/im/plugin/demo/DemoPresenceMapping.java
src/com/android/im/app/BrandingResources.java
src/com/android/im/app/FrontDoorPlugin.java [deleted file]
src/com/android/im/app/ImApp.java
src/com/android/im/app/ImPluginHelper.java [new file with mode: 0644]
src/com/android/im/app/LandingPage.java [new file with mode: 0644]
src/com/android/im/app/ProviderListItem.java [new file with mode: 0644]
src/com/android/im/engine/SmsService.java
src/com/android/im/imps/CirChannel.java
src/com/android/im/imps/CustomPasswordDigest.java
src/com/android/im/imps/CustomPresenceMapping.java
src/com/android/im/imps/DefaultPresenceMapping.java
src/com/android/im/imps/HttpCirChannel.java
src/com/android/im/imps/ImpsConnectionConfig.java
src/com/android/im/imps/ImpsContactListManager.java
src/com/android/im/imps/ImpsPresenceUtils.java
src/com/android/im/imps/PasswordDigest.java [deleted file]
src/com/android/im/imps/PresenceMapping.java [deleted file]
src/com/android/im/imps/PresencePollingManager.java
src/com/android/im/imps/SmsCirChannel.java
src/com/android/im/imps/StandardPasswordDigest.java
src/com/android/im/imps/TcpCirChannel.java
src/com/android/im/service/AndroidHeartBeatService.java
src/com/android/im/service/AndroidSmsService.java
src/com/android/im/service/RemoteImService.java

index d72d6dc..4eecd43 100644 (file)
@@ -16,21 +16,9 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) \
                        src/com/android/im/ISubscriptionListener.aidl \
                        src/com/android/im/IConnectionCreationListener.aidl \
 
-# Filter out the plugin and samples when build IM.apk
-LOCAL_SRC_FILES := $(filter-out \
-                       plugin/% samples/% \
-                       ,$(LOCAL_SRC_FILES))
-
 LOCAL_PACKAGE_NAME := IM
 
-# TODO: Remove dependency of application on the test runner (android.test.runner)
-# library.
-LOCAL_JAVA_LIBRARIES := android.test.runner \
-                        com.android.im.plugin \
-#                        com.android.providers.im.plugin
-
-# LOCAL_REQUIRED_MODULES must go before BUILD_PACKAGE
-LOCAL_REQUIRED_MODULES := libwbxml libwbxml_jni ImProvider
+LOCAL_JNI_SHARED_LIBRARIES := libwbxml_jni
 
 #Disable building the APK; we are checking in the pre-built version which
 #contains the credential plug-in instead. Note the libwbxml_jni has to be
index c0b26aa..7d4bdcd 100644 (file)
              android:label="@string/im_label"
              android:icon="@drawable/ic_launcher_im"
              android:taskAffinity="android.task.im">
-        <uses-library android:name="com.android.im.plugin" />
-        <!-- TODO: Remove dependency of application on the test runner
-             (android.test) library. -->
-        <uses-library android:name="android.test.runner" />
-
-        <service android:name=".app.FrontDoorPlugin">
-            <intent-filter>
-                <action android:name="android.im.plugin" />
-            </intent-filter>
-        </service>
 
         <service android:name=".service.RemoteImService"
             android:process="android.process.im"
             </intent-filter>
         </activity>
 
-        <activity android:name=".app.AccountActivity">
+        <activity android:name=".app.LandingPage">
+           <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.dir/im-providers" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".app.AccountActivity"
+            android:configChanges="orientation|keyboardHidden"
+            android:windowSoftInputMode="stateUnchanged">
             <intent-filter>
                 <action android:name="android.intent.action.EDIT" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
 
-        <activity android:name=".app.SigningInActivity">
+        <activity android:name=".app.SigningInActivity"
+            android:configChanges="orientation|keyboardHidden">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </receiver>
 
+        <!--Plug-in Sevice started-->
+        <!--
+        <service android:name="com.android.im.plugin.demo.DemoImPlugin">
+            <intent-filter>
+                <action android:name="com.android.im.plugin" />
+            </intent-filter>
+            <meta-data android:name="com.android.im.provider_name"
+                android:value="Demo"/>
+            <meta-data android:name="com.android.im.provider_full_name"
+                android:value="Demo IM Provider"/>
+            <meta-data android:name="com.android.im.signup_url"
+                android:value="http://xxx.xxx.xxx"/>
+        </service>
+        -->
+        <!--Plug-in Service end-->
+
     </application>
 
 </manifest>
index 4836f0d..c9450c1 100644 (file)
@@ -9,6 +9,7 @@ include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES :=          \
     src/wbxml_parser.cpp    \
+    src/wbxml_encoder.cpp   \
     src/imps_encoder.cpp    \
     src/csp13tags_hash.c    \
     src/csp13values_hash.c  \
@@ -29,7 +30,7 @@ LOCAL_MODULE_TAGS := $(wbxml_module_tags)
 
 LOCAL_MODULE := libwbxml
 
-include $(BUILD_SHARED_LIBRARY)
+include $(BUILD_STATIC_LIBRARY)
 
 # xml2wbxml library: libxml2wbxml.so
 # ---------------------------------------
@@ -49,9 +50,10 @@ LOCAL_CFLAGS += -DPLATFORM_ANDROID
 
 LOCAL_SHARED_LIBRARIES +=   \
     libutils                \
-    libwbxml                \
     libexpat
 
+LOCAL_STATIC_LIBRARIES := libwbxml
+
 LOCAL_MODULE_TAGS := $(wbxml_module_tags)
 
 LOCAL_MODULE := libxml2wbxml
@@ -79,13 +81,14 @@ LOCAL_CFLAGS += -DSUPPORT_SYNCML
 LOCAL_SRC_FILES += test/syncml_parser_test.cpp
 
 LOCAL_SHARED_LIBRARIES +=   \
-    libwbxml                \
     libxml2wbxml            \
     libembunit              \
     libutils                \
     libexpat
 
-LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_LIBRARIES := libwbxml
+
+LOCAL_MODULE_TAGS := tests
 
 LOCAL_MODULE := wbxmltest
 
@@ -100,16 +103,15 @@ LOCAL_SRC_FILES :=      \
 
 LOCAL_C_INCLUDES :=         \
     $(LOCAL_PATH)/include   \
-    external/expat/lib \
     $(JNI_H_INCLUDE)
 
 LOCAL_CFLAGS += -DPLATFORM_ANDROID
 
 LOCAL_SHARED_LIBRARIES +=   \
-    libwbxml                \
     libutils                \
     libcutils                \
-    libexpat
+
+LOCAL_STATIC_LIBRARIES := libwbxml
 
 LOCAL_MODULE_TAGS := $(wbxml_module_tags)
 
index c7300b0..fda9651 100644 (file)
@@ -25,7 +25,7 @@ class ImpsWbxmlEncoder : public WbxmlEncoder
 {
 public:
     ImpsWbxmlEncoder(int publicid) :
-        mPublicId(publicid)
+        WbxmlEncoder(publicid)
     {
         reset();
     }
@@ -53,28 +53,12 @@ public:
     EncoderError endElement();
 
 private:
-    int mPublicId;
     int mTagCodePage;
-    string mResult;
     string mCurrElement;
     int mDepth;
 
-    EncoderError encodeInteger(const char *chars, int len);
-    EncoderError encodeDatetime(const char *chars, int len);
     EncoderError encodeString(const char *chars, int len);
     EncoderError encodeAttrib(const char *name, const char *value);
-    void encodeInlinedStr(const char *s, int len);
-    void encodeMbuint(uint32_t i);
-
-    void appendResult(int ch)
-    {
-        mResult += (char)ch;
-    }
-
-    void appendResult(const char *s, int len)
-    {
-        mResult.append(s, len);
-    }
 };
 
 #endif
index a1b653a..bbd21c8 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <stdint.h>
 #include "wbxml_const.h"
+#include "wbxml_stl.h"
+
 
 class WbxmlHandler
 {
@@ -43,6 +45,8 @@ enum EncoderError {
 class WbxmlEncoder
 {
 public:
+    WbxmlEncoder(int publicId):mPublicId(publicId) {}
+
     virtual ~WbxmlEncoder() {}
 
     void setWbxmlHandler(WbxmlHandler * handler)
@@ -60,8 +64,44 @@ public:
      */
     virtual void reset() = 0;
 
+    static bool isXmlWhitespace(int ch);
+    static bool parseUint(const char * s, int len, uint32_t *res);
+
 protected:
     WbxmlHandler * mHandler;
+    int mPublicId;
+
+    EncoderError encodeInteger(const char *chars, int len);
+    EncoderError encodeDatetime(const char *chars, int len);
+    void encodeInlinedStr(const char *s, int len);
+    void encodeMbuint(uint32_t i);
+
+    void clearResult()
+    {
+        mResult.clear();
+    }
+
+    void appendResult(int ch)
+    {
+        mResult += (char)ch;
+    }
+
+    void appendResult(const char *s, int len)
+    {
+        mResult.append(s, len);
+    }
+
+    void sendResult();
+
+    /**
+     * Append a string into the string table, return the index of the string in
+     * the string table.
+     */
+    int appendToStringTable(const char *s);
+
+private:
+    string mResult;
+    vector<string> mStringTable;
 };
 
 #endif
index 959486c..26a30ee 100644 (file)
@@ -42,34 +42,14 @@ static const XmlnsPrefix csp13xmlns[] = {
     { "http://www.openmobilealliance.org/DTD/IMPS-TRC", 0x0d },
 };
 
-static bool isXmlWhitespace(int ch)
-{
-    return ch == ' ' || ch == 9 || ch == 0xd || ch == 0xa;
-}
-
 static bool isDatetimeElement(const char *name)
 {
     return (strcmp("DateTime", name) == 0 || strcmp("DeliveryTime", name) == 0);
 }
 
-static bool parseUint(const char * s, int len, uint32_t *res)
-{
-    string str(s, len);
-    char *end;
-    long long val = strtoll(str.c_str(), &end, 10);
-    if (*end != 0 || val < 0 || val > 0xFFFFFFFFU) {
-        return false;
-    }
-    *res = (uint32_t)val;
-    return true;
-}
-
 void ImpsWbxmlEncoder::reset()
 {
-    // WBXML 1.3, UTF-8, no string table
-    char header[4] = {0x03, (char)mPublicId, 0x6A, 0x00};
-    mResult.clear();
-    mResult.append(header, sizeof(header));
+    clearResult();
 
     mTagCodePage = 0;
     mCurrElement.clear();
@@ -82,9 +62,11 @@ EncoderError ImpsWbxmlEncoder::startElement(const char *name, const char **atts)
         return ERROR_INVALID_DATA;
     }
 
+    bool isUnknownTag = false;
     int stag = csp13TagNameToKey(name);
     if (stag == -1) {
-        return ERROR_UNSUPPORTED_TAG;
+        stag = TOKEN_LITERAL;
+        isUnknownTag = true;
     }
     mDepth++;
     mCurrElement = name;
@@ -102,6 +84,11 @@ EncoderError ImpsWbxmlEncoder::startElement(const char *name, const char **atts)
         stag |= 0x80;   // has attribute
     }
     appendResult(stag);
+
+    if (isUnknownTag) {
+        int index = appendToStringTable(name);
+        encodeMbuint(index);
+    }
     if (stag & 0x80) {
         for (size_t i = 0; atts[i]; i += 2) {
             EncoderError err = encodeAttrib(atts[i], atts[i + 1]);
@@ -164,69 +151,9 @@ EncoderError ImpsWbxmlEncoder::endElement()
     }
     appendResult(TOKEN_END);
     mCurrElement.clear();
-    if (mDepth == 0 && mHandler) {
-        mHandler->wbxmlData(mResult.c_str(), mResult.size());
-    }
-    return NO_ERROR;
-}
-
-EncoderError ImpsWbxmlEncoder::encodeInteger(const char *chars, int len)
-{
-    uint32_t val;
-    if (!parseUint(chars, len, &val)) {
-        return ERROR_INVALID_INTEGER_VALUE;
-    }
-
-    appendResult(TOKEN_OPAQUE);
-    uint32_t mask = 0xff000000U;
-    int numBytes = 4;
-    while (!(val & mask) && mask) {
-        numBytes--;
-        mask >>= 8;
-    }
-    if (!numBytes) {
-        // Zero value. We generate at least 1 byte OPAQUE data.
-        // libwbxml2 generates 0 byte long OPAQUE data (0xC3 0x00) in this case.
-        numBytes = 1;
-    }
-
-    appendResult(numBytes);
-    while (numBytes) {
-        numBytes--;
-        appendResult((val >> (numBytes * 8)) & 0xff);
-    }
-
-    return NO_ERROR;
-}
-
-EncoderError ImpsWbxmlEncoder::encodeDatetime(const char *chars, int len)
-{
-    // to make life easier we accept only yyyymmddThhmmssZ
-    if (len != 16 || chars[8] != 'T' || chars[15] != 'Z') {
-        return ERROR_INVALID_DATETIME_VALUE;
+    if (mDepth == 0) {
+        sendResult();
     }
-    appendResult(TOKEN_OPAQUE);
-    appendResult(6);
-
-    uint32_t year, month, day, hour, min, sec;
-    if (!parseUint(chars, 4, &year)
-            || !parseUint(chars + 4, 2, &month)
-            || !parseUint(chars + 6, 2, &day)
-            || !parseUint(chars + 9, 2, &hour)
-            || !parseUint(chars + 11,2, &min)
-            || !parseUint(chars + 13,2, &sec)) {
-        return ERROR_INVALID_DATETIME_VALUE;
-    }
-    if (year > 4095 || month > 12 || day > 31 || hour > 23 || min > 59 || sec > 59) {
-        return ERROR_INVALID_DATETIME_VALUE;
-    }
-
-    appendResult(year >> 6);
-    appendResult(((year & 0x3f) << 2) | (month >> 2));
-    appendResult(((month & 0x3) << 6) | (day << 1) | (hour >> 4));
-    appendResult(((hour & 0xf) << 4) | (min >> 2));
-    appendResult(((min & 0x2) << 6) | sec);
-    appendResult('Z');
     return NO_ERROR;
 }
 
@@ -251,7 +178,9 @@ EncoderError ImpsWbxmlEncoder::encodeAttrib(const char *name, const char *value)
         return ERROR_UNSUPPORTED_ATTR;
     }
     int valueLen = strlen(value);
-    for (size_t i = 0; i < sizeof(csp13xmlns) / sizeof(csp13xmlns[0]); i++) {
+    size_t csp13xmlnsCount = sizeof(csp13xmlns) / sizeof(csp13xmlns[0]);
+    size_t i;
+    for (i = 0; i < csp13xmlnsCount; i++) {
         const char * prefix = csp13xmlns[i].prefix;
         int prefixLen = strlen(csp13xmlns[i].prefix);
         if (strncmp(prefix, value, prefixLen) == 0) {
@@ -262,31 +191,12 @@ EncoderError ImpsWbxmlEncoder::encodeAttrib(const char *name, const char *value)
             return NO_ERROR;
         }
     }
+    if (i == csp13xmlnsCount) {
+        // not predefined attribute
+        appendResult(TOKEN_LITERAL);
+        int index = appendToStringTable(name);
+        encodeMbuint(index);
+    }
     encodeInlinedStr(value, valueLen);
     return NO_ERROR;
 }
-
-void ImpsWbxmlEncoder::encodeInlinedStr(const char *s, int len)
-{
-    // TODO: move this to WbxmlEncoder
-    // TODO: handle ENTITY
-    appendResult(TOKEN_STR_I);
-    appendResult(s, len);
-    appendResult('\0');
-}
-
-void ImpsWbxmlEncoder::encodeMbuint(uint32_t val)
-{
-    char buf[32 / 7 + 1];   // each byte holds up to 7 bits
-    int i = sizeof(buf);
-
-    buf[--i] = val & 0x7f;
-    val >>= 7;
-    while ((i > 0) && (val & 0x7f)) {
-        buf[--i] = 0x80 | (val & 0x7f);
-        val >>= 7;
-    }
-
-    appendResult(buf + i, sizeof(buf) - i);
-}
-
diff --git a/libwbxml/src/wbxml_encoder.cpp b/libwbxml/src/wbxml_encoder.cpp
new file mode 100644 (file)
index 0000000..c84b90e
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2009 Esmertec AG.
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "imps_encoder.h"
+
+bool WbxmlEncoder::isXmlWhitespace(int ch)
+{
+    return ch == ' ' || ch == 9 || ch == 0xd || ch == 0xa;
+}
+
+bool WbxmlEncoder::parseUint(const char * s, int len, uint32_t *res)
+{
+    string str(s, len);
+    char *end;
+    long long val = strtoll(str.c_str(), &end, 10);
+    if (*end != 0 || val < 0 || val > 0xFFFFFFFFU) {
+        return false;
+    }
+    *res = (uint32_t)val;
+    return true;
+}
+
+EncoderError WbxmlEncoder::encodeInteger(const char *chars, int len)
+{
+    uint32_t val;
+    if (!parseUint(chars, len, &val)) {
+        return ERROR_INVALID_INTEGER_VALUE;
+    }
+
+    appendResult(TOKEN_OPAQUE);
+    uint32_t mask = 0xff000000U;
+    int numBytes = 4;
+    while (!(val & mask) && mask) {
+        numBytes--;
+        mask >>= 8;
+    }
+    if (!numBytes) {
+        // Zero value. We generate at least 1 byte OPAQUE data.
+        // libwbxml2 generates 0 byte long OPAQUE data (0xC3 0x00) in this case.
+        numBytes = 1;
+    }
+
+    appendResult(numBytes);
+    while (numBytes) {
+        numBytes--;
+        appendResult((val >> (numBytes * 8)) & 0xff);
+    }
+
+    return NO_ERROR;
+}
+
+EncoderError WbxmlEncoder::encodeDatetime(const char *chars, int len)
+{
+    // to make life easier we accept only yyyymmddThhmmssZ
+    if (len != 16 || chars[8] != 'T' || chars[15] != 'Z') {
+        return ERROR_INVALID_DATETIME_VALUE;
+    }
+    appendResult(TOKEN_OPAQUE);
+    appendResult(6);
+
+    uint32_t year, month, day, hour, min, sec;
+    if (!parseUint(chars, 4, &year)
+            || !parseUint(chars + 4, 2, &month)
+            || !parseUint(chars + 6, 2, &day)
+            || !parseUint(chars + 9, 2, &hour)
+            || !parseUint(chars + 11,2, &min)
+            || !parseUint(chars + 13,2, &sec)) {
+        return ERROR_INVALID_DATETIME_VALUE;
+    }
+    if (year > 4095 || month > 12 || day > 31 || hour > 23 || min > 59 || sec > 59) {
+        return ERROR_INVALID_DATETIME_VALUE;
+    }
+
+    appendResult(year >> 6);
+    appendResult(((year & 0x3f) << 2) | (month >> 2));
+    appendResult(((month & 0x3) << 6) | (day << 1) | (hour >> 4));
+    appendResult(((hour & 0xf) << 4) | (min >> 2));
+    appendResult(((min & 0x2) << 6) | sec);
+    appendResult('Z');
+    return NO_ERROR;
+}
+
+void WbxmlEncoder::encodeInlinedStr(const char *s, int len)
+{
+    // TODO: handle ENTITY
+    appendResult(TOKEN_STR_I);
+    appendResult(s, len);
+    appendResult('\0');
+}
+
+void WbxmlEncoder::encodeMbuint(uint32_t val)
+{
+    char buf[32 / 7 + 1];   // each byte holds up to 7 bits
+    int i = sizeof(buf);
+
+    buf[--i] = val & 0x7f;
+    val >>= 7;
+    while ((i > 0) && (val & 0x7f)) {
+        buf[--i] = 0x80 | (val & 0x7f);
+        val >>= 7;
+    }
+
+    appendResult(buf + i, sizeof(buf) - i);
+}
+
+int WbxmlEncoder::appendToStringTable(const char *s)
+{
+    int stringTableSize = mStringTable.size();
+    int offset = 0;
+    
+    // search the string table to find if the string already exist
+    int index = 0;
+    for (; index < stringTableSize; index++) {
+        if (mStringTable[index] == s) {
+            break;
+        }
+        offset += mStringTable[index].length();
+        ++offset; // '\0' for each string in the table
+    }
+    if (index == stringTableSize) {
+        // not found, insert a new one
+        mStringTable.push_back(s);
+    }
+    return offset;
+}
+
+void WbxmlEncoder::sendResult()
+{
+    if (mHandler) {
+        string data;
+        string tmp = mResult;
+        mResult = data;
+
+        // WBXML 1.3, UTF-8
+        char header[3] = { 0x03, (char) mPublicId, 0x6A };
+        appendResult(header, 3);
+
+        // calculate the length of string table
+        int len = 0;
+        for (int i = 0; i < mStringTable.size(); i++) {
+            len += mStringTable[i].length();
+            ++len;
+        }
+
+        encodeMbuint(len);
+
+        // encode each string in the table
+        for (int i = 0; i < mStringTable.size(); i++) {
+            mResult += mStringTable[i];
+            mResult += '\0';
+        }
+
+        mResult += tmp;
+
+        mHandler->wbxmlData(mResult.c_str(), mResult.size());
+    }
+}
diff --git a/plugin/Android.mk b/plugin/Android.mk
deleted file mode 100644 (file)
index 28ccd21..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#
-# Copyright (C) 2008 Esmertec AG.
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-LOCAL_PATH := $(call my-dir)
-
-# the library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-            $(call all-subdir-java-files) \
-            com/android/im/plugin/IImPlugin.aidl \
-            com/android/im/plugin/IPasswordDigest.aidl \
-            com/android/im/plugin/IPresenceMapping.aidl \
-
-LOCAL_MODULE:= com.android.im.plugin
-
-include $(BUILD_JAVA_LIBRARY)
similarity index 91%
rename from plugin/com/android/im/plugin/IImPlugin.aidl
rename to plugin/com/android/im/plugin/ImPlugin.java
index b641e86..27ad319 100644 (file)
@@ -16,7 +16,9 @@
  */
 package com.android.im.plugin;
 
-interface IImPlugin {
+import java.util.Map;
+
+public interface ImPlugin {
     /**
      * Gets a map of branding resources for the provider. The keys are defined
      * in {@link com.android.im.plugin.BrandingResourceIDs}. The values are the
@@ -24,7 +26,7 @@ interface IImPlugin {
      *
      * @return The map of branding resources.
      */
-    Map getResourceMap();
+    Map<Integer, Integer> getResourceMap();
 
     /**
      * Gets an array of IDs of the smiley icons. The sequence of the IDs must
@@ -42,5 +44,5 @@ interface IImPlugin {
      *
      * @return the configuration for the provider.
      */
-    Map getProviderConfig();
+    Map<String, String> getProviderConfig();
 }
 
 package com.android.im.plugin;
 
+import com.android.im.engine.ImException;
+
 /**
  * The password digest method used in IMPS login transaction.
  */
-interface IPasswordDigest {
+public interface PasswordDigest {
     /**
      * Gets an array of supported digest schema.
      *
@@ -35,6 +37,7 @@ interface IPasswordDigest {
      * @param nonce The nonce string returned by the server.
      * @param password The user password.
      * @return The digest bytes of the password.
+     * @throws ImException
      */
-    String digest(String schema, String nonce, String password);
+    String digest(String schema, String nonce, String password) throws ImException;
 }
  */
 package com.android.im.plugin;
 
+import java.util.Map;
+
 /**
  * The methods used to map presence value sent in protocol to predefined
  * presence status.
  */
-interface IPresenceMapping {
+public interface PresenceMapping {
     /**
      * Tells if the mapping needs all presence values sent in protocol. If this
      * method returns true, the framework will pass all the presence values
@@ -43,7 +45,7 @@ interface IPresenceMapping {
      * @see #requireAllPresenceValues()
      */
     int getPresenceStatus(boolean onlineStatus, String userAvailability,
-            in Map allValues);
+            Map<String, Object> allValues);
 
     /**
      * Gets the value of &lt;OnlineStatus&gt; will be sent to the server when
@@ -71,7 +73,7 @@ interface IPresenceMapping {
      * @param status the predefined status.
      * @return The extra values that will be sent to the server.
      */
-    Map getExtra(int status);
+    Map<String, Object> getExtra(int status);
 
     /**
      * Gets an array of the supported presence status. The client can only update
diff --git a/res/color/landing_page_text.xml b/res/color/landing_page_text.xml
new file mode 100644 (file)
index 0000000..6e967d9
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true" android:color="#ff000000"/>
+    <item android:state_selected="true" android:color="#ff000000"/>
+    <item android:state_pressed="true" android:color="#ff000000"/>
+    <item android:color="#ffffffff"/>
+</selector>
diff --git a/res/color/landing_page_text_secondary.xml b/res/color/landing_page_text_secondary.xml
new file mode 100644 (file)
index 0000000..78cc390
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true" android:color="#ff000000"/>
+    <item android:state_selected="true" android:color="#ff000000"/>
+    <item android:state_pressed="true" android:color="#ff000000"/>
+    <item android:color="#ffbebebe"/>
+</selector>
similarity index 75%
rename from samples/PluginDemo/res/drawable/emo_im_cool.png
rename to res/drawable/default_background.9.png
index d8eeb34..33cb551 100644 (file)
Binary files a/samples/PluginDemo/res/drawable/emo_im_cool.png and b/res/drawable/default_background.9.png differ
diff --git a/res/layout/account_view.xml b/res/layout/account_view.xml
new file mode 100644 (file)
index 0000000..411c844
--- /dev/null
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<com.android.im.app.ProviderListItem
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="?android:attr/listPreferredItemHeight">
+
+    <ImageView
+        android:id="@+id/providerIcon"
+        android:layout_gravity="center_vertical"
+        android:scaleType="fitXY"
+        android:paddingLeft="5dip"
+        android:paddingRight="2dip"
+        android:layout_width="39dip"
+        android:layout_height="32dip"/>
+
+    <LinearLayout
+        android:id="@+id/underBubble"
+        android:orientation="horizontal"
+        android:layout_weight="1"
+        android:layout_width="0dip"
+        android:layout_height="fill_parent">    
+
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_weight="1"
+            android:layout_width="0dip"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical">    
+
+            <LinearLayout
+                android:orientation="horizontal"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content">
+
+                <TextView android:id="@+id/providerName"
+                    android:textColor="@color/landing_page_text"
+                    android:textAppearance="?android:attr/textAppearanceLarge"
+                    android:textStyle="bold"
+                    android:singleLine="true"
+                    android:layout_weight="1.0"
+                    android:ellipsize="marquee"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+                <TextView android:id="@+id/conversations"
+                    android:textAppearance="?android:attr/textAppearanceMedium"
+                    android:textColor="@color/landing_page_text_secondary"
+                    android:singleLine="true"
+                    android:paddingRight="3dip"
+                    android:paddingLeft="5dip"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+            </LinearLayout>
+
+            <TextView android:id="@+id/loginName"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+                android:textColor="@color/landing_page_text"
+                android:ellipsize="marquee"
+                android:singleLine="true"
+                android:layout_width="fill_parent"
+               android:layout_height="wrap_content"/>
+        </LinearLayout>
+        <ImageView
+            android:id="@+id/statusIcon"
+            android:scaleType="fitXY"
+            android:paddingRight="6dip"
+            android:paddingLeft="6dip"
+            android:layout_weight="0"
+            android:layout_gravity="center_vertical"
+            android:layout_width="30dip"
+            android:layout_height="18dip"/>
+    </LinearLayout>
+</com.android.im.app.ProviderListItem>
\ No newline at end of file
index 01e3b50..619dff1 100644 (file)
@@ -76,6 +76,7 @@
 
     <ExpandableListView android:id="@+id/contactsList"
         android:layout_width="fill_parent"
-        android:layout_height="fill_parent" />
+        android:layout_height="fill_parent"
+        android:nextFocusUp="@id/statusDropDownButton" />
 
 </com.android.im.app.ContactListView>
index b64d990..00dc0b9 100644 (file)
@@ -58,7 +58,7 @@
                 android:layout_height="wrap_content">
 
                 <TextView android:id="@+id/line1"
-                    android:maxLines="1"
+                    android:singleLine="true"
                     android:layout_width="0dip"
                     android:layout_weight="1"
                     android:layout_height="wrap_content"
@@ -76,7 +76,7 @@
             </LinearLayout>
 
             <TextView android:id="@+id/line2"
-                android:maxLines="1"
+                android:singleLine="true"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
                 android:textAppearance="?android:attr/textAppearanceSmall"
index a8bfad1..6bf5768 100644 (file)
     android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft">
 
     <TextView android:id="@+id/text1"
-        android:maxLines="1"
+        android:singleLine="true"
         android:layout_width="0dip"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:layout_weight="1"
+        android:ellipsize="marquee"
         android:textAppearance="?android:attr/textAppearanceLarge" />
 
     <TextView android:id="@+id/text2"
-        android:maxLines="1"
+        android:singleLine="true"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
index fb366b8..0b8b8b8 100644 (file)
     Home screen. This is a noun. -->
     <string name="im_label">IM</string>
 
+    <!-- These strings displayed on the landing page. -->
+    <!-- The title of the landing page.-->
+    <string name="landing_page_title">Chat - Select an account</string>
+
+    <!-- Landing page screen menu and context menu items. -->
+    <!-- Conext menu item: add a new account.-->
+    <string name="menu_add_account">Add account</string>
+    <!-- Conext menu item: edit an account.-->
+    <string name="menu_edit_account">Edit account</string>
+    <!-- Conext menu item: remove an account.-->
+    <string name="menu_remove_account">Remove account</string>
+    <!-- Screen menu item: sign out all service.-->
+    <string name="menu_sign_out_all">Sign out all</string>
+
+    <!-- These strings displayed on the landing page. -->
+    <!-- The title of the landing page.-->
+    <string name="choose_account_title">Chat - Select an account</string>
+    <!-- Displays the number of ongoing chats on the landing page.-->
+    <string name="conversations">(%1$d)</string>
+
     <!-- Sign in progress screen menu items.-->
     <!-- Screen menu item on the sign-in progress screen. It allows the user to cancel signing in.-->
     <string name="menu_cancel_signin">Cancel signin</string>
     <!-- Strings for the confirm dialogs-->
     <!-- The title of the confirm dialog which asks the user to continue or cancel an operation such as block a contact, remove a contact.-->
     <string name="confirm">Confirm</string>
+    <!-- This is the message displayed in the confirm dialog when the user choose to sign out all service -->
+    <string name="signout_all_confirm_message">Do you want to sign out all services?</string>
     <!-- This is the message displayed in the confirm dialog that opens when user clicks to delete a contact in the contact list screen.-->
     <string name="confirm_delete_contact">The contact \"<xliff:g id="user">%1$s</xliff:g>\" will be deleted.</string>
     <!-- This is the message displayed in the confirm dialog that opens when user clicks to  block a contact in the contact list screen.-->
diff --git a/samples/PluginDemo/Android.mk b/samples/PluginDemo/Android.mk
deleted file mode 100644 (file)
index 46fe534..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := samples
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files) \
-
-LOCAL_PACKAGE_NAME := ImPluginDemo
-
-LOCAL_JAVA_LIBRARIES := com.android.im.plugin
-
-include $(BUILD_PACKAGE)
diff --git a/samples/PluginDemo/AndroidManifest.xml b/samples/PluginDemo/AndroidManifest.xml
deleted file mode 100644 (file)
index eaebd68..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright (C) 2008 Esmertec Inc.
- * Copyright (C) 2008 The Android Open Source Project
-
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.im.plugin.demo" android:sharedUserId="android.uid.im">
-
-    <application android:taskAffinity="android.task.im">
-
-        <uses-library android:name="com.android.im.plugin" />
-
-        <service android:name=".DemoImPlugin">
-            <intent-filter>
-                <action android:name="com.android.im.plugin" />
-            </intent-filter>
-            <meta-data android:name="com.android.im.provider_name"
-                android:value="Demo"/>
-            <meta-data android:name="com.android.im.provider_full_name"
-                android:value="Demo IM Provider"/>
-            <meta-data android:name="com.android.im.signup_url"
-                android:value="http://xxx.xxx.xxx"/>
-        </service>
-
-    </application>
-
-</manifest>
diff --git a/samples/PluginDemo/res/drawable/chat.png b/samples/PluginDemo/res/drawable/chat.png
deleted file mode 100755 (executable)
index be844fd..0000000
Binary files a/samples/PluginDemo/res/drawable/chat.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/chat_new.png b/samples/PluginDemo/res/drawable/chat_new.png
deleted file mode 100755 (executable)
index f31ba59..0000000
Binary files a/samples/PluginDemo/res/drawable/chat_new.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_angel.png b/samples/PluginDemo/res/drawable/emo_im_angel.png
deleted file mode 100644 (file)
index c34dfa6..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_angel.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_crying.png b/samples/PluginDemo/res/drawable/emo_im_crying.png
deleted file mode 100644 (file)
index 1cafdb3..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_crying.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_embarrassed.png b/samples/PluginDemo/res/drawable/emo_im_embarrassed.png
deleted file mode 100644 (file)
index e4db963..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_embarrassed.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_foot_in_mouth.png b/samples/PluginDemo/res/drawable/emo_im_foot_in_mouth.png
deleted file mode 100644 (file)
index 09d1fba..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_foot_in_mouth.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_happy.png b/samples/PluginDemo/res/drawable/emo_im_happy.png
deleted file mode 100644 (file)
index b86602a..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_happy.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_kissing.png b/samples/PluginDemo/res/drawable/emo_im_kissing.png
deleted file mode 100644 (file)
index 56378f6..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_kissing.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_laughing.png b/samples/PluginDemo/res/drawable/emo_im_laughing.png
deleted file mode 100644 (file)
index 980bf28..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_laughing.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_lips_are_sealed.png b/samples/PluginDemo/res/drawable/emo_im_lips_are_sealed.png
deleted file mode 100644 (file)
index f2de993..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_lips_are_sealed.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_money_mouth.png b/samples/PluginDemo/res/drawable/emo_im_money_mouth.png
deleted file mode 100644 (file)
index 08c53fd..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_money_mouth.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_sad.png b/samples/PluginDemo/res/drawable/emo_im_sad.png
deleted file mode 100644 (file)
index 31c08d0..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_sad.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_surprised.png b/samples/PluginDemo/res/drawable/emo_im_surprised.png
deleted file mode 100644 (file)
index abe8c7a..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_surprised.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_tongue_sticking_out.png b/samples/PluginDemo/res/drawable/emo_im_tongue_sticking_out.png
deleted file mode 100644 (file)
index 6f0f47b..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_tongue_sticking_out.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_undecided.png b/samples/PluginDemo/res/drawable/emo_im_undecided.png
deleted file mode 100644 (file)
index eb4f8c5..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_undecided.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_winking.png b/samples/PluginDemo/res/drawable/emo_im_winking.png
deleted file mode 100644 (file)
index 568562a..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_winking.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_wtf.png b/samples/PluginDemo/res/drawable/emo_im_wtf.png
deleted file mode 100644 (file)
index 41dd47f..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_wtf.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/emo_im_yelling.png b/samples/PluginDemo/res/drawable/emo_im_yelling.png
deleted file mode 100644 (file)
index c3c8612..0000000
Binary files a/samples/PluginDemo/res/drawable/emo_im_yelling.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/im_logo.png b/samples/PluginDemo/res/drawable/im_logo.png
deleted file mode 100644 (file)
index 764d189..0000000
Binary files a/samples/PluginDemo/res/drawable/im_logo.png and /dev/null differ
diff --git a/samples/PluginDemo/res/drawable/im_logo_splashscr.png b/samples/PluginDemo/res/drawable/im_logo_splashscr.png
deleted file mode 100644 (file)
index 1b7ee6f..0000000
Binary files a/samples/PluginDemo/res/drawable/im_logo_splashscr.png and /dev/null differ
diff --git a/samples/PluginDemo/res/values-cs/strings.xml b/samples/PluginDemo/res/values-cs/strings.xml
deleted file mode 100644 (file)
index a0cdf4c..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Přidat kontakt"</string>
-    <string name="menu_remove_contact">"Smazat kontakt"</string>
-    <string name="menu_block_contact">"Blokovat"</string>
-    <string name="menu_contact_list">"Seznam kontaktů"</string>
-    <string name="menu_start_chat">"Odeslat zprávu"</string>
-    <string name="menu_view_profile">"Info o kamarádovi"</string>
-    <string name="menu_end_conversation">"Konec konverzace"</string>
-    <string name="menu_switch_chats">"Přepnout chat"</string>
-    <string name="menu_insert_smiley">"Vložit emotikony"</string>
-    <string name="sign_up">"Zřízení nového účtu"</string>
-    <string name="check_save_password">"Pokud je váš telefon ukraden nebo jej ztratíte, přejděte v zájmu vlastní bezpečnosti na počítači na web a změňte své heslo."</string>
-    <string name="buddy_list_title">"Seznam kontaktů – <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Uživatelské jméno:"</string>
-    <string name="ongoing_conversation">"Konverzace (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Kontaktní informace"</string>
-    <string name="presence_available">"Povoleno"</string>
-    <string name="add_contact_title">"Přidat kontakt"</string>
-    <string name="input_contact_label">"Jméno osoby, kterou chcete přidat:"</string>
-    <string name="invite_label">"Přidat kamaráda"</string>
-  <string-array name="smiley_names">
-    <item>"Happy"</item>
-    <item>"Smutný"</item>
-    <item>"Mrkající"</item>
-    <item>"Vypláznutý jazyk"</item>
-    <item>"Překvapený"</item>
-    <item>"Pusa"</item>
-    <item>"Hej!"</item>
-    <item>"Cool"</item>
-    <item>"Cinkání zlaťáků"</item>
-    <item>"Šlápota v úsměvu"</item>
-    <item>"V rozpacích"</item>
-    <item>"Andílek"</item>
-    <item>"Nerozhodný"</item>
-    <item>"Rozplakaný"</item>
-    <item>"Ani muk"</item>
-    <item>"Smějící se"</item>
-    <item>"Zmatený"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-da/strings.xml b/samples/PluginDemo/res/values-da/strings.xml
deleted file mode 100644 (file)
index c0646bf..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Tilføj kontaktperson"</string>
-    <string name="menu_remove_contact">"Slet kontaktperson"</string>
-    <string name="menu_block_contact">"Bloker"</string>
-    <string name="menu_contact_list">"Liste over kontaktpersoner"</string>
-    <string name="menu_start_chat">"Send IM"</string>
-    <string name="menu_view_profile">"Venneoplysninger"</string>
-    <string name="menu_end_conversation">"Afslut samtale"</string>
-    <string name="menu_switch_chats">"Skift chats"</string>
-    <string name="menu_insert_smiley">"Indsæt humørikoner"</string>
-    <string name="sign_up">"Få en ny konto"</string>
-    <string name="check_save_password">"For din egen sikkerheds skyld skal du gå til webstedet på din computer og ændre din adgangskode, hvis du mister din telefon, eller den bliver stjålet."</string>
-    <string name="buddy_list_title">"Liste over kontaktpersoner – <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Brugernavn:"</string>
-    <string name="ongoing_conversation">"Samtaler (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Kontaktoplysninger"</string>
-    <string name="presence_available">"Ledig"</string>
-    <string name="add_contact_title">"Tilføj kontaktperson"</string>
-    <string name="input_contact_label">"Skærmnavn for den person du ønsker at tilføje:"</string>
-    <string name="invite_label">"Tilføj ven"</string>
-  <string-array name="smiley_names">
-    <item>"Glad"</item>
-    <item>"Trist"</item>
-    <item>"Blinker"</item>
-    <item>"Rækker tunge"</item>
-    <item>"Overrasket"</item>
-    <item>"Kysser"</item>
-    <item>"Råber"</item>
-    <item>"Sej"</item>
-    <item>"Pengeglad"</item>
-    <item>"Forlegen"</item>
-    <item>"Flov"</item>
-    <item>"Engel"</item>
-    <item>"Uafklaret"</item>
-    <item>"Græder"</item>
-    <item>"Lukket med syv segl"</item>
-    <item>"Griner"</item>
-    <item>"Forvirret"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-de/strings.xml b/samples/PluginDemo/res/values-de/strings.xml
deleted file mode 100644 (file)
index 773ad05..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Kontakt hinzufügen"</string>
-    <string name="menu_remove_contact">"Kontakt löschen"</string>
-    <string name="menu_block_contact">"Blockieren"</string>
-    <string name="menu_contact_list">"Kontaktliste"</string>
-    <string name="menu_start_chat">"IM senden"</string>
-    <string name="menu_view_profile">"Buddy Info"</string>
-    <string name="menu_end_conversation">"Gespräch beenden"</string>
-    <string name="menu_switch_chats">"Chats wechseln"</string>
-    <string name="menu_insert_smiley">"Emoticons einfügen"</string>
-    <string name="sign_up">"Ein neues Konto erhalten"</string>
-    <string name="check_save_password">"Zu Ihrer Sicherheit: Wenn Sie Ihr Telefon verloren haben oder es gestohlen wurde, rufen Sie die Website auf Ihrem Computer auf und ändern Sie Ihr Passwort."</string>
-    <string name="buddy_list_title">"Kontaktliste - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Benutzername:"</string>
-    <string name="ongoing_conversation">"Gespräche (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Kontaktinformationen"</string>
-    <string name="presence_available">"Verfügbar"</string>
-    <string name="add_contact_title">"Kontakt hinzufügen"</string>
-    <string name="input_contact_label">"Displayname der Person, die Sie hinzufügen möchten:"</string>
-    <string name="invite_label">"Buddy hinzufügen"</string>
-  <string-array name="smiley_names">
-    <item>"Glücklich"</item>
-    <item>"Traurig"</item>
-    <item>"Zwinkern"</item>
-    <item>"Zunge rausstrecken"</item>
-    <item>"Überrascht"</item>
-    <item>"Kuss"</item>
-    <item>"Schreien"</item>
-    <item>"Cool"</item>
-    <item>"Lass Taten sprechen"</item>
-    <item>"Fettnäpfchen"</item>
-    <item>"Peinlich berührt"</item>
-    <item>"Engel"</item>
-    <item>"Unentschlossen"</item>
-    <item>"Weinen"</item>
-    <item>"Versiegelte Lippen"</item>
-    <item>"Lachen"</item>
-    <item>"Verwirrt"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-el/strings.xml b/samples/PluginDemo/res/values-el/strings.xml
deleted file mode 100644 (file)
index f2dbfd0..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Προσθήκη επαφής"</string>
-    <string name="menu_remove_contact">"Διαγραφή επαφής"</string>
-    <string name="menu_block_contact">"Αποκλεισμός"</string>
-    <string name="menu_contact_list">"Λίστα επαφών"</string>
-    <string name="menu_start_chat">"Αποστολή άμεσων μηνυμάτων (IM)"</string>
-    <string name="menu_view_profile">"Πληροφορίες φίλου"</string>
-    <string name="menu_end_conversation">"Τερματισμός συνομιλίας"</string>
-    <string name="menu_switch_chats">"Αλλαγή συζητήσεων"</string>
-    <string name="menu_insert_smiley">"Εισαγωγή εικονιδίων emoticons"</string>
-    <string name="sign_up">"Αποκτήστε νέο λογαριασμό"</string>
-    <string name="check_save_password">"Για την ασφάλειά σας, εάν το τηλέφωνό σας χαθεί ή κλαπεί, μεταβείτε στον ιστότοπο στον υπολογιστή σας και αλλάξτε τον κωδικό πρόσβασης."</string>
-    <string name="buddy_list_title">"Λίστα επαφών - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Όνομα χρήστη:"</string>
-    <string name="ongoing_conversation">"Συνομιλίες (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Πληροφορίας επικοινωνίας"</string>
-    <string name="presence_available">"Διαθέσιμος/η"</string>
-    <string name="add_contact_title">"Προσθήκη επαφής"</string>
-    <string name="input_contact_label">"Το ψευδώνυμο του ατόμου που θέλετε να προσθέσετε:"</string>
-    <string name="invite_label">"Προσθήκη φίλου"</string>
-  <string-array name="smiley_names">
-    <item>"Είμαι χαρούμενος"</item>
-    <item>"Είμαι λυπημένος"</item>
-    <item>"Κλείνω το μάτι"</item>
-    <item>"Κοροϊδεύω"</item>
-    <item>"Είμαι έκπληκτος"</item>
-    <item>"Φιλάω"</item>
-    <item>"Φωνάζω"</item>
-    <item>"Cool"</item>
-    <item>"Κάνω τα λόγια μου πράξη"</item>
-    <item>"Είπα ανοησία"</item>
-    <item>"Ντρέπομαι"</item>
-    <item>"Αγγελούδι"</item>
-    <item>"Δεν έχω αποφασίσει"</item>
-    <item>"Κλαίω"</item>
-    <item>"Δεν αποκαλύπτω τίποτα"</item>
-    <item>"Γελάω"</item>
-    <item>"Είμαι μπερδεμένος"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-es-rUS/strings.xml b/samples/PluginDemo/res/values-es-rUS/strings.xml
deleted file mode 100644 (file)
index 6aedb55..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Agregar contacto"</string>
-    <string name="menu_remove_contact">"Eliminar contacto"</string>
-    <string name="menu_block_contact">"Bloquear"</string>
-    <string name="menu_contact_list">"Lista de contactos"</string>
-    <string name="menu_start_chat">"Enviar mensajería instantánea"</string>
-    <string name="menu_view_profile">"Información de Buddy"</string>
-    <string name="menu_end_conversation">"Finalizar conversación"</string>
-    <string name="menu_switch_chats">"Modificar chats"</string>
-    <string name="menu_insert_smiley">"Insertar emoticones"</string>
-    <string name="sign_up">"Obtén una cuenta nueva"</string>
-    <string name="check_save_password">"Para tu seguridad, si pierdes o te roban el teléfono, ingresa al sitio web desde tu computadora y cambia la contraseña."</string>
-    <string name="buddy_list_title">"Lista de contactos - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Nombre de usuario:"</string>
-    <string name="ongoing_conversation">"Conversaciones (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Información de contacto"</string>
-    <string name="presence_available">"Disponible"</string>
-    <string name="add_contact_title">"Agregar contacto"</string>
-    <string name="input_contact_label">"Nombre de pantalla de la persona que deseas agregar:"</string>
-    <string name="invite_label">"Agregar Buddy"</string>
-  <string-array name="smiley_names">
-    <item>"Feliz"</item>
-    <item>"Triste"</item>
-    <item>"Guiñando un ojo"</item>
-    <item>"Con la lengua afuera"</item>
-    <item>"Sorprendido"</item>
-    <item>"Besando"</item>
-    <item>"Gritando"</item>
-    <item>"En la onda"</item>
-    <item>"Dinero en boca"</item>
-    <item>"Meter la pata"</item>
-    <item>"Avergonzado"</item>
-    <item>"Ángel"</item>
-    <item>"Indeciso"</item>
-    <item>"Llorando"</item>
-    <item>"Los labios están cerrados"</item>
-    <item>"Riendo"</item>
-    <item>"Confundido"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-es/strings.xml b/samples/PluginDemo/res/values-es/strings.xml
deleted file mode 100644 (file)
index 5f0338d..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Añadir contacto"</string>
-    <string name="menu_remove_contact">"Eliminar contacto"</string>
-    <string name="menu_block_contact">"Bloquear"</string>
-    <string name="menu_contact_list">"Lista de contactos"</string>
-    <string name="menu_start_chat">"Enviar MI"</string>
-    <string name="menu_view_profile">"Información de amigo"</string>
-    <string name="menu_end_conversation">"Finalizar conversación"</string>
-    <string name="menu_switch_chats">"Cambiar de chat"</string>
-    <string name="menu_insert_smiley">"Insertar emoticonos"</string>
-    <string name="sign_up">"Obtener una cuenta nueva"</string>
-    <string name="check_save_password">"Si pierdes el teléfono o te lo roban, te recomendamos por seguridad que accedas al sitio web desde tu equipo y cambies la contraseña."</string>
-    <string name="buddy_list_title">"Lista de contactos - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Nombre de usuario:"</string>
-    <string name="ongoing_conversation">"Conversaciones (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Información de contacto"</string>
-    <string name="presence_available">"Disponible"</string>
-    <string name="add_contact_title">"Añadir contacto"</string>
-    <string name="input_contact_label">"Nombre de pantalla de la persona que quieres añadir:"</string>
-    <string name="invite_label">"Añadir amigo"</string>
-  <string-array name="smiley_names">
-    <item>"Contento"</item>
-    <item>"Triste"</item>
-    <item>"Guiño"</item>
-    <item>"Sacando la lengua"</item>
-    <item>"Sorprendido"</item>
-    <item>"Besando"</item>
-    <item>"Gritando"</item>
-    <item>"Atractivo"</item>
-    <item>"Dinero en la boca"</item>
-    <item>"Metedura de pata"</item>
-    <item>"Avergonzado"</item>
-    <item>"Ángel"</item>
-    <item>"Indeciso"</item>
-    <item>"Llorando"</item>
-    <item>"Labios sellados"</item>
-    <item>"Riendo"</item>
-    <item>"Confuso"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-fr/strings.xml b/samples/PluginDemo/res/values-fr/strings.xml
deleted file mode 100644 (file)
index 7d6af6f..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Ajouter un contact"</string>
-    <string name="menu_remove_contact">"Supprimer un contact"</string>
-    <string name="menu_block_contact">"Bloquer"</string>
-    <string name="menu_contact_list">"Liste de contacts"</string>
-    <string name="menu_start_chat">"Envoyer un message instantané"</string>
-    <string name="menu_view_profile">"Infos sur le contact"</string>
-    <string name="menu_end_conversation">"Terminer la conversation"</string>
-    <string name="menu_switch_chats">"Changer de chat"</string>
-    <string name="menu_insert_smiley">"Insérer une émoticône"</string>
-    <string name="sign_up">"Créer un nouveau compte"</string>
-    <string name="check_save_password">"Pour votre sécurité, en cas de vol ou de perte de votre téléphone, rendez-vous sur le site Web depuis votre ordinateur et modifiez votre mot de passe."</string>
-    <string name="buddy_list_title">"Liste de contacts :<xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Nom d\'utilisateur :"</string>
-    <string name="ongoing_conversation">"Conversations (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Infos sur le contact"</string>
-    <string name="presence_available">"Disponible"</string>
-    <string name="add_contact_title">"Ajouter le contact"</string>
-    <string name="input_contact_label">"Identifiant du contact que vous souhaitez ajouter :"</string>
-    <string name="invite_label">"Ajouter un contact"</string>
-  <string-array name="smiley_names">
-    <item>"Content"</item>
-    <item>"Triste"</item>
-    <item>"Clin d\'œil"</item>
-    <item>"Tire la langue"</item>
-    <item>"Surpris"</item>
-    <item>"Bisou"</item>
-    <item>"Hurle"</item>
-    <item>"Cool"</item>
-    <item>"Argent"</item>
-    <item>"Embarrassé"</item>
-    <item>"Gêné"</item>
-    <item>"Ange"</item>
-    <item>"Indécis"</item>
-    <item>"Pleure"</item>
-    <item>"Motus et bouche cousue"</item>
-    <item>"Rigole"</item>
-    <item>"Confus"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-it/strings.xml b/samples/PluginDemo/res/values-it/strings.xml
deleted file mode 100644 (file)
index 622b5ef..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Aggiungi contatto"</string>
-    <string name="menu_remove_contact">"Elimina contatto"</string>
-    <string name="menu_block_contact">"Blocca"</string>
-    <string name="menu_contact_list">"Elenco contatti"</string>
-    <string name="menu_start_chat">"Invia msg chat"</string>
-    <string name="menu_view_profile">"Info amico"</string>
-    <string name="menu_end_conversation">"Termina conversazione"</string>
-    <string name="menu_switch_chats">"Cambia conversazione"</string>
-    <string name="menu_insert_smiley">"Inserisci emoticon"</string>
-    <string name="sign_up">"Ottieni un nuovo account"</string>
-    <string name="check_save_password">"Per la tua sicurezza, in caso di perdita o furto del telefono visita il sito web da un computer e cambia la password."</string>
-    <string name="buddy_list_title">"Elenco contatti - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Nome utente:"</string>
-    <string name="ongoing_conversation">"Conversazioni (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Info contatto"</string>
-    <string name="presence_available">"Disponibile"</string>
-    <string name="add_contact_title">"Aggiungi contatto"</string>
-    <string name="input_contact_label">"Nome visualizzato della persona da aggiungere:"</string>
-    <string name="invite_label">"Aggiungi amico"</string>
-  <string-array name="smiley_names">
-    <item>"Felice"</item>
-    <item>"Triste"</item>
-    <item>"Occhiolino"</item>
-    <item>"Linguaccia"</item>
-    <item>"Sorpreso"</item>
-    <item>"Bacio"</item>
-    <item>"Urlo"</item>
-    <item>"Fico"</item>
-    <item>"Fatti, non parole"</item>
-    <item>"Gaffe"</item>
-    <item>"Imbarazzato"</item>
-    <item>"Angelo"</item>
-    <item>"Indeciso"</item>
-    <item>"Piango"</item>
-    <item>"Labbra cucite"</item>
-    <item>"Risata"</item>
-    <item>"Confuso"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-ja/strings.xml b/samples/PluginDemo/res/values-ja/strings.xml
deleted file mode 100644 (file)
index 844b6df..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"連絡先を追加"</string>
-    <string name="menu_remove_contact">"連絡先を削除"</string>
-    <string name="menu_block_contact">"ブロック"</string>
-    <string name="menu_contact_list">"連絡先リスト"</string>
-    <string name="menu_start_chat">"チャットを送信"</string>
-    <string name="menu_view_profile">"友だち情報"</string>
-    <string name="menu_end_conversation">"チャット終了"</string>
-    <string name="menu_switch_chats">"チャットを切り替え"</string>
-    <string name="menu_insert_smiley">"絵文字を挿入"</string>
-    <string name="sign_up">"新しいアカウントを取得"</string>
-    <string name="check_save_password">"セキュリティ保護のため、携帯電話を紛失したり盗まれたりした場合は、パソコンからウェブサイトにアクセスしてパスワードを変更してください。"</string>
-    <string name="buddy_list_title">"連絡先リスト - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"ユーザー名:"</string>
-    <string name="ongoing_conversation">"チャット (<xliff:g id="NUMBER">%1$d</xliff:g>件)"</string>
-    <string name="contact_profile_title">"連絡先情報"</string>
-    <string name="presence_available">"オンライン"</string>
-    <string name="add_contact_title">"連絡先を追加"</string>
-    <string name="input_contact_label">"追加する人のスクリーンネーム:"</string>
-    <string name="invite_label">"友だちを追加"</string>
-  <string-array name="smiley_names">
-    <item>"ハッピー"</item>
-    <item>"悲しい"</item>
-    <item>"ウィンク"</item>
-    <item>"アッカンベー"</item>
-    <item>"びっくり"</item>
-    <item>"キス"</item>
-    <item>"激怒"</item>
-    <item>"クール"</item>
-    <item>"気持ち悪い"</item>
-    <item>"しまった"</item>
-    <item>"恥ずかしい"</item>
-    <item>"天使"</item>
-    <item>"迷う"</item>
-    <item>"泣く"</item>
-    <item>"お口にチャック"</item>
-    <item>"笑顔"</item>
-    <item>"混乱"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-ko/strings.xml b/samples/PluginDemo/res/values-ko/strings.xml
deleted file mode 100644 (file)
index 85e0b75..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"연락처 추가"</string>
-    <string name="menu_remove_contact">"연락처 삭제"</string>
-    <string name="menu_block_contact">"차단"</string>
-    <string name="menu_contact_list">"연락처 목록"</string>
-    <string name="menu_start_chat">"채팅하기"</string>
-    <string name="menu_view_profile">"친구 정보"</string>
-    <string name="menu_end_conversation">"대화 종료"</string>
-    <string name="menu_switch_chats">"채팅 전환"</string>
-    <string name="menu_insert_smiley">"이모티콘 삽입"</string>
-    <string name="sign_up">"새 계정 만들기"</string>
-    <string name="check_save_password">"휴대전화를 잃어버렸거나 도난당한 경우에는 보안을 위해 컴퓨터에서 웹사이트를 방문하여 비밀번호를 변경하세요."</string>
-    <string name="buddy_list_title">"연락처 목록 - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"사용자 이름:"</string>
-    <string name="ongoing_conversation">"대화(<xliff:g id="NUMBER">%1$d</xliff:g>개)"</string>
-    <string name="contact_profile_title">"연락처 정보"</string>
-    <string name="presence_available">"온라인"</string>
-    <string name="add_contact_title">"연락처 추가"</string>
-    <string name="input_contact_label">"추가할 사람의 대화명:"</string>
-    <string name="invite_label">"친구 추가"</string>
-  <string-array name="smiley_names">
-    <item>"행복해"</item>
-    <item>"슬퍼요"</item>
-    <item>"윙크"</item>
-    <item>"메롱"</item>
-    <item>"헉!"</item>
-    <item>"키스"</item>
-    <item>"아악"</item>
-    <item>"멋지네"</item>
-    <item>"으이구"</item>
-    <item>"실수했네"</item>
-    <item>"당황"</item>
-    <item>"천사"</item>
-    <item>"결정하기 어렵군"</item>
-    <item>"엉엉엉"</item>
-    <item>"비밀로 할게"</item>
-    <item>"하하하"</item>
-    <item>"어리둥절"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-nb/strings.xml b/samples/PluginDemo/res/values-nb/strings.xml
deleted file mode 100644 (file)
index 57056b6..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Legg til kontakt"</string>
-    <string name="menu_remove_contact">"Fjern kontakt"</string>
-    <string name="menu_block_contact">"Blokker kontakt"</string>
-    <string name="menu_contact_list">"Kontaktliste"</string>
-    <string name="menu_start_chat">"Start samtale"</string>
-    <string name="menu_view_profile">"Vis profil"</string>
-    <string name="menu_end_conversation">"Avslutt samtale"</string>
-    <string name="menu_switch_chats">"Bytt mellom samtaler"</string>
-    <string name="menu_insert_smiley">"Sett inn smilefjes"</string>
-    <string name="sign_up">"Mangler du konto?"</string>
-    <string name="check_save_password">"Av sikkerhetsgrunner, gå til nettstedet og endre passordet om telefonen blir tapt eller stjåler."</string>
-    <string name="buddy_list_title">"Kontaktliste - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Brukernavn:"</string>
-    <string name="ongoing_conversation">"Pågående samtaler (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Kontaktprofil"</string>
-    <string name="presence_available">"Tilgjengelig"</string>
-    <string name="add_contact_title">"Legg til kontakt"</string>
-    <string name="input_contact_label">"E-postadresse til den du ønsker å invitere:"</string>
-    <string name="invite_label">"Send invitasjon"</string>
-  <string-array name="smiley_names">
-    <item>"Glad"</item>
-    <item>"Trist"</item>
-    <item>"Blunker"</item>
-    <item>"Rekker tunge"</item>
-    <item>"Overrasket"</item>
-    <item>"Kyss"</item>
-    <item>"Roper"</item>
-    <item>"Kul"</item>
-    <item>"Pengemunn"</item>
-    <item>"Fot i munnen"</item>
-    <item>"Flau"</item>
-    <item>"Engel"</item>
-    <item>"Usikker"</item>
-    <item>"Gråter"</item>
-    <item>"Stille som graven"</item>
-    <item>"Ler"</item>
-    <item>"Forvirret"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-nl/strings.xml b/samples/PluginDemo/res/values-nl/strings.xml
deleted file mode 100644 (file)
index 5fe916c..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Contact toevoegen"</string>
-    <string name="menu_remove_contact">"Contact verwijderen"</string>
-    <string name="menu_block_contact">"Blokkeren"</string>
-    <string name="menu_contact_list">"Lijst met contacten"</string>
-    <string name="menu_start_chat">"Chat verzenden"</string>
-    <string name="menu_view_profile">"Buddygegevens"</string>
-    <string name="menu_end_conversation">"Conversatie beëindigen"</string>
-    <string name="menu_switch_chats">"Schakelen tussen chats"</string>
-    <string name="menu_insert_smiley">"Emoticons invoegen"</string>
-    <string name="sign_up">"Een nieuw account verkrijgen"</string>
-    <string name="check_save_password">"Als u uw telefoon verliest of als deze wordt gestolen, moet u voor uw veiligheid naar de website gaan op uw computer en uw wachtwoord wijzigen."</string>
-    <string name="buddy_list_title">"Lijst met contacten - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Gebruikersnaam:"</string>
-    <string name="ongoing_conversation">"Conversaties (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Contactgegevens"</string>
-    <string name="presence_available">"Beschikbaar"</string>
-    <string name="add_contact_title">"Contact toevoegen"</string>
-    <string name="input_contact_label">"Schermnaam van de persoon die u wilt toevoegen:"</string>
-    <string name="invite_label">"Buddy toevoegen"</string>
-  <string-array name="smiley_names">
-    <item>"Blij"</item>
-    <item>"Bedroefd"</item>
-    <item>"Knipoog"</item>
-    <item>"Tong uitsteken"</item>
-    <item>"Verrast"</item>
-    <item>"Kussend"</item>
-    <item>"Schreeuwend"</item>
-    <item>"Cool"</item>
-    <item>"Geldzoeker"</item>
-    <item>"Mond vol tanden"</item>
-    <item>"Beschaamd"</item>
-    <item>"Engel"</item>
-    <item>"Twijfelend"</item>
-    <item>"Huilend"</item>
-    <item>"Lippen op elkaar"</item>
-    <item>"Lachend"</item>
-    <item>"Verward"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"Err:502"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-pl/strings.xml b/samples/PluginDemo/res/values-pl/strings.xml
deleted file mode 100644 (file)
index b53ce03..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Dodaj kontakt"</string>
-    <string name="menu_remove_contact">"Usuń kontakt"</string>
-    <string name="menu_block_contact">"Zablokuj"</string>
-    <string name="menu_contact_list">"Lista kontaktów"</string>
-    <string name="menu_start_chat">"Wyślij wiadomość przez czat"</string>
-    <string name="menu_view_profile">"Informacje o znajomym"</string>
-    <string name="menu_end_conversation">"Zakończ rozmowę"</string>
-    <string name="menu_switch_chats">"Przełącz czaty"</string>
-    <string name="menu_insert_smiley">"Wstaw buźkę"</string>
-    <string name="sign_up">"Utwórz nowe konto"</string>
-    <string name="check_save_password">"Ze względów bezpieczeństwa w przypadku zgubienia lub kradzieży telefonu odwiedź witrynę internetową ze swojego komputera i zmień hasło."</string>
-    <string name="buddy_list_title">"Lista kontaktów – <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Nazwa użytkownika:"</string>
-    <string name="ongoing_conversation">"Rozmowy: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
-    <string name="contact_profile_title">"Informacje kontaktowe"</string>
-    <string name="presence_available">"Dostępny"</string>
-    <string name="add_contact_title">"Dodaj kontakt"</string>
-    <string name="input_contact_label">"Widoczna nazwa dodawanej osoby:"</string>
-    <string name="invite_label">"Dodaj znajomego"</string>
-  <string-array name="smiley_names">
-    <item>"Wesoły"</item>
-    <item>"Smutny"</item>
-    <item>"Mruga"</item>
-    <item>"Pokazuje język"</item>
-    <item>"Zdziwienie"</item>
-    <item>"Całuje"</item>
-    <item>"Krzyczy"</item>
-    <item>"Na luzie"</item>
-    <item>"Pazerny"</item>
-    <item>"Nietaktowny"</item>
-    <item>"Zakłopotanie"</item>
-    <item>"Anioł"</item>
-    <item>"Niezdecydowany"</item>
-    <item>"Płacze"</item>
-    <item>"Milczy jak grób"</item>
-    <item>"Śmieje się"</item>
-    <item>"Zmieszany"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-pt-rPT/strings.xml b/samples/PluginDemo/res/values-pt-rPT/strings.xml
deleted file mode 100644 (file)
index e3002e9..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Adicionar contacto"</string>
-    <string name="menu_remove_contact">"Eliminar contacto"</string>
-    <string name="menu_block_contact">"Bloquear"</string>
-    <string name="menu_contact_list">"Lista de contactos"</string>
-    <string name="menu_start_chat">"Enviar MI"</string>
-    <string name="menu_view_profile">"Informações do amigo"</string>
-    <string name="menu_end_conversation">"Terminar conversa"</string>
-    <string name="menu_switch_chats">"Trocar chats"</string>
-    <string name="menu_insert_smiley">"Inserir ícones expressivos"</string>
-    <string name="sign_up">"Obter uma nova conta"</string>
-    <string name="check_save_password">"Para sua segurança, caso perca o telefone ou este seja roubado, aceda ao Web site no computador e altere a sua palavra-passe."</string>
-    <string name="buddy_list_title">"Lista de contactos - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Nome de utilizador:"</string>
-    <string name="ongoing_conversation">"Conversas (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Informações de contacto"</string>
-    <string name="presence_available">"Disponível"</string>
-    <string name="add_contact_title">"Adicionar contacto"</string>
-    <string name="input_contact_label">"Pseudónimo da pessoa que pretende adicionar:"</string>
-    <string name="invite_label">"Adicionar amigo"</string>
-  <string-array name="smiley_names">
-    <item>"Feliz"</item>
-    <item>"Triste"</item>
-    <item>"A piscar o olho"</item>
-    <item>"Língua de fora"</item>
-    <item>"Surpreendido"</item>
-    <item>"Beijoqueiro"</item>
-    <item>"A gritar"</item>
-    <item>"Fixe"</item>
-    <item>"Interesseiro"</item>
-    <item>"Arrependido"</item>
-    <item>"Envergonhado"</item>
-    <item>"Anjo"</item>
-    <item>"Indeciso"</item>
-    <item>"Chorão"</item>
-    <item>"Boca fechada"</item>
-    <item>"Risonho"</item>
-    <item>"Confuso"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-pt/strings.xml b/samples/PluginDemo/res/values-pt/strings.xml
deleted file mode 100644 (file)
index 0b1eeb8..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Adicionar contato"</string>
-    <string name="menu_remove_contact">"Excluir contato"</string>
-    <string name="menu_block_contact">"Bloquear"</string>
-    <string name="menu_contact_list">"Lista de contatos"</string>
-    <string name="menu_start_chat">"Enviar mensagem instantânea"</string>
-    <string name="menu_view_profile">"Informações do amigo"</string>
-    <string name="menu_end_conversation">"Encerrar conversa"</string>
-    <string name="menu_switch_chats">"Alternar bate-papos"</string>
-    <string name="menu_insert_smiley">"Inserir emoticons"</string>
-    <string name="sign_up">"Obter uma nova conta"</string>
-    <string name="check_save_password">"Para a sua segurança, se o seu telefone for perdido ou roubado, acesse o site no seu computador e altere a sua senha."</string>
-    <string name="buddy_list_title">"Lista de contatos - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Nome de usuário:"</string>
-    <string name="ongoing_conversation">"Conversas (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Informações de contato"</string>
-    <string name="presence_available">"Disponível"</string>
-    <string name="add_contact_title">"Adicionar contato"</string>
-    <string name="input_contact_label">"Apelido da pessoa que você deseja adicionar:"</string>
-    <string name="invite_label">"Adicionar amigo"</string>
-  <string-array name="smiley_names">
-    <item>"Feliz"</item>
-    <item>"Triste"</item>
-    <item>"Piscando"</item>
-    <item>"Mostrando a língua"</item>
-    <item>"Surpreso"</item>
-    <item>"Beijando"</item>
-    <item>"Gritando"</item>
-    <item>"Tranquilo"</item>
-    <item>"Louco por dinheiro"</item>
-    <item>"Falei besteira"</item>
-    <item>"Envergonhado"</item>
-    <item>"Anjo"</item>
-    <item>"Indeciso"</item>
-    <item>"Chorando"</item>
-    <item>"Boca fechada"</item>
-    <item>"Rindo"</item>
-    <item>"Confuso"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-ru/strings.xml b/samples/PluginDemo/res/values-ru/strings.xml
deleted file mode 100644 (file)
index 4c0f836..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Добавить контакт"</string>
-    <string name="menu_remove_contact">"Удалить контакт"</string>
-    <string name="menu_block_contact">"Заблокировать"</string>
-    <string name="menu_contact_list">"Список контактов"</string>
-    <string name="menu_start_chat">"Отправить сообщение чата"</string>
-    <string name="menu_view_profile">"О приятеле"</string>
-    <string name="menu_end_conversation">"Закончить разговор"</string>
-    <string name="menu_switch_chats">"Сменить чат"</string>
-    <string name="menu_insert_smiley">"Вставить значки настроений"</string>
-    <string name="sign_up">"Получить новый аккаунт"</string>
-    <string name="check_save_password">"В случае потери или кражи телефона для обеспечения вашей безопасности перейдите со своего компьютера на веб-сайт и поменяйте пароль."</string>
-    <string name="buddy_list_title">"Список контактов – <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Имя пользователя:"</string>
-    <string name="ongoing_conversation">"Разговоров: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
-    <string name="contact_profile_title">"Сведения о контакте"</string>
-    <string name="presence_available">"На месте"</string>
-    <string name="add_contact_title">"Добавить контакт"</string>
-    <string name="input_contact_label">"Псевдоним человека, которого необходимо добавить:"</string>
-    <string name="invite_label">"Добавить приятеля"</string>
-  <string-array name="smiley_names">
-    <item>"Веселый"</item>
-    <item>"Грустный"</item>
-    <item>"Подмигивает"</item>
-    <item>"Показывает язык"</item>
-    <item>"Удивление"</item>
-    <item>"Поцелуй"</item>
-    <item>"Кричит"</item>
-    <item>"Крутой"</item>
-    <item>"Молчание – золото"</item>
-    <item>"В замешательстве"</item>
-    <item>"Смущение"</item>
-    <item>"Ангел"</item>
-    <item>"Нерешительный"</item>
-    <item>"Плачет"</item>
-    <item>"Не скажу"</item>
-    <item>"Смех"</item>
-    <item>"Озадаченный"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-sv/strings.xml b/samples/PluginDemo/res/values-sv/strings.xml
deleted file mode 100644 (file)
index 7614eac..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Lägg till kontakt"</string>
-    <string name="menu_remove_contact">"Ta bort kontakt"</string>
-    <string name="menu_block_contact">"Blockera"</string>
-    <string name="menu_contact_list">"Kontaktlista"</string>
-    <string name="menu_start_chat">"Skicka chattmeddelande"</string>
-    <string name="menu_view_profile">"Kompisinfo"</string>
-    <string name="menu_end_conversation">"Avsluta konversation"</string>
-    <string name="menu_switch_chats">"Byt chatt"</string>
-    <string name="menu_insert_smiley">"Infoga uttryckssymboler"</string>
-    <string name="sign_up">"Öppna ett nytt konto"</string>
-    <string name="check_save_password">"Om din telefon blir stulen besöker du webbplatsen via datorn och ändrar lösenordet. Detta är för din egen säkerhet."</string>
-    <string name="buddy_list_title">"Kontaktlista – <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Användarnamn:"</string>
-    <string name="ongoing_conversation">"Konversationer (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Kontaktinfo"</string>
-    <string name="presence_available">"Tillgänglig"</string>
-    <string name="add_contact_title">"Lägg till kontakt"</string>
-    <string name="input_contact_label">"Signatur för den du vill lägga till:"</string>
-    <string name="invite_label">"Lägg till kompis"</string>
-  <string-array name="smiley_names">
-    <item>"Glad"</item>
-    <item>"Ledsen"</item>
-    <item>"Blinkar"</item>
-    <item>"Lipar"</item>
-    <item>"Förvånad"</item>
-    <item>"Pussar"</item>
-    <item>"Skriker"</item>
-    <item>"Cool"</item>
-    <item>"Dollarmun"</item>
-    <item>"Bortgjord"</item>
-    <item>"Generad"</item>
-    <item>"Ängel"</item>
-    <item>"Tveksam"</item>
-    <item>"Gråter"</item>
-    <item>"Hemlis"</item>
-    <item>"Skrattar"</item>
-    <item>"Förvirrad"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-tr/strings.xml b/samples/PluginDemo/res/values-tr/strings.xml
deleted file mode 100644 (file)
index 5f3d45f..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"Kişi Ekle"</string>
-    <string name="menu_remove_contact">"Kişiyi Sil"</string>
-    <string name="menu_block_contact">"Engelle"</string>
-    <string name="menu_contact_list">"Kişi Listesi"</string>
-    <string name="menu_start_chat">"IM Gönder"</string>
-    <string name="menu_view_profile">"Arkadaş Bilgileri"</string>
-    <string name="menu_end_conversation">"İleti Dizisini Sonlandır"</string>
-    <string name="menu_switch_chats">"Sohbetler Arasında Geçiş Yap"</string>
-    <string name="menu_insert_smiley">"İfade Ekle"</string>
-    <string name="sign_up">"Yeni hesap al"</string>
-    <string name="check_save_password">"Telefonunuz kaybolur veya çalınırsa, güvenliğiniz için bilgisayarınızdan Web sitesine gidin ve şifrenizi değiştirin."</string>
-    <string name="buddy_list_title">"Kişi Listesi - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"Kullanıcı adı:"</string>
-    <string name="ongoing_conversation">"Konuşmalar (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"Kişi Bilgileri"</string>
-    <string name="presence_available">"Müsait"</string>
-    <string name="add_contact_title">"Kişi Ekle"</string>
-    <string name="input_contact_label">"Eklemek istediğiniz kişinin ekran adı:"</string>
-    <string name="invite_label">"Arkadaş Ekle"</string>
-  <string-array name="smiley_names">
-    <item>"Mutlu"</item>
-    <item>"Üzgün"</item>
-    <item>"Göz Kırpma"</item>
-    <item>"Dil çıkarmış"</item>
-    <item>"Şaşırmış"</item>
-    <item>"Öpücük"</item>
-    <item>"Bağırma"</item>
-    <item>"Sakin"</item>
-    <item>"Para ağızlı"</item>
-    <item>"Ayak ağızda"</item>
-    <item>"Utanmış"</item>
-    <item>"Melek"</item>
-    <item>"Kararsız"</item>
-    <item>"Ağlama"</item>
-    <item>"Dudakları mühürlü"</item>
-    <item>"Gülme"</item>
-    <item>"Kafası karışmış"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-zh-rCN/strings.xml b/samples/PluginDemo/res/values-zh-rCN/strings.xml
deleted file mode 100644 (file)
index c096514..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"添加联系人"</string>
-    <string name="menu_remove_contact">"删除联系人"</string>
-    <string name="menu_block_contact">"阻止"</string>
-    <string name="menu_contact_list">"联系人列表"</string>
-    <string name="menu_start_chat">"发送即时消息"</string>
-    <string name="menu_view_profile">"好友信息"</string>
-    <string name="menu_end_conversation">"结束会话"</string>
-    <string name="menu_switch_chats">"切换聊天"</string>
-    <string name="menu_insert_smiley">"插入表情符"</string>
-    <string name="sign_up">"获取新帐户"</string>
-    <string name="check_save_password">"为了您的安全,如果您的手机遗失或被窃,请通过您的计算机访问网站并更改您的密码。"</string>
-    <string name="buddy_list_title">"联系人列表 - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"用户名:"</string>
-    <string name="ongoing_conversation">"会话 (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"联系人信息"</string>
-    <string name="presence_available">"有空"</string>
-    <string name="add_contact_title">"添加联系人"</string>
-    <string name="input_contact_label">"您希望添加的联系人的用户名:"</string>
-    <string name="invite_label">"添加好友"</string>
-  <string-array name="smiley_names">
-    <item>"幸福"</item>
-    <item>"悲伤"</item>
-    <item>"眨眼"</item>
-    <item>"吐舌头"</item>
-    <item>"惊讶"</item>
-    <item>"亲吻"</item>
-    <item>"大喊"</item>
-    <item>"酷"</item>
-    <item>"财迷"</item>
-    <item>"说错了话"</item>
-    <item>"尴尬"</item>
-    <item>"天使"</item>
-    <item>"犹豫"</item>
-    <item>"哭泣"</item>
-    <item>"保密"</item>
-    <item>"大笑"</item>
-    <item>"困惑"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values-zh-rTW/strings.xml b/samples/PluginDemo/res/values-zh-rTW/strings.xml
deleted file mode 100644 (file)
index 2c48338..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">"新增聯絡人"</string>
-    <string name="menu_remove_contact">"刪除聯絡人"</string>
-    <string name="menu_block_contact">"封鎖"</string>
-    <string name="menu_contact_list">"聯絡人清單"</string>
-    <string name="menu_start_chat">"傳送即時訊息"</string>
-    <string name="menu_view_profile">"好友資訊"</string>
-    <string name="menu_end_conversation">"結束會話"</string>
-    <string name="menu_switch_chats">"切換即時通訊"</string>
-    <string name="menu_insert_smiley">"插入表情符號"</string>
-    <string name="sign_up">"取得新帳戶"</string>
-    <string name="check_save_password">"為了安全起見,如果電話遺失或遭竊,請使用電腦前往該網站並變更密碼。"</string>
-    <string name="buddy_list_title">"聯絡人清單 - <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
-    <string name="label_username">"使用者名稱:"</string>
-    <string name="ongoing_conversation">"會話 (<xliff:g id="NUMBER">%1$d</xliff:g>)"</string>
-    <string name="contact_profile_title">"聯絡人資訊"</string>
-    <string name="presence_available">"可用"</string>
-    <string name="add_contact_title">"新增聯絡人"</string>
-    <string name="input_contact_label">"要新增之聯絡人在畫面上的名稱:"</string>
-    <string name="invite_label">"新增好友"</string>
-  <string-array name="smiley_names">
-    <item>"開心"</item>
-    <item>"傷心"</item>
-    <item>"眨眼"</item>
-    <item>"吐舌頭"</item>
-    <item>"驚訝"</item>
-    <item>"紅唇"</item>
-    <item>"大喊"</item>
-    <item>"酷"</item>
-    <item>"滿嘴錢"</item>
-    <item>"說錯話"</item>
-    <item>"害羞"</item>
-    <item>"天使"</item>
-    <item>"還沒決定"</item>
-    <item>"嚎啕大哭"</item>
-    <item>"不要告訴別人"</item>
-    <item>"開懷大笑"</item>
-    <item>"疑惑"</item>
-  </string-array>
-  <string-array name="smiley_texts">
-    <item>":-)"</item>
-    <item>":-("</item>
-    <item>";-)"</item>
-    <item>":-P"</item>
-    <item>"=-O"</item>
-    <item>":-*"</item>
-    <item>":O"</item>
-    <item>"B-)"</item>
-    <item>":-$"</item>
-    <item>":-!"</item>
-    <item>":-["</item>
-    <item>"O:-)"</item>
-    <item>":-\\"</item>
-    <item>":\'("</item>
-    <item>":-X"</item>
-    <item>":-D"</item>
-    <item>"o_O"</item>
-  </string-array>
-</resources>
diff --git a/samples/PluginDemo/res/values/strings.xml b/samples/PluginDemo/res/values/strings.xml
deleted file mode 100644 (file)
index 7afa4ab..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright (C) 2008 Esmertec Inc.
- * Copyright (C) 2008 The Android Open Source Project
-
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="menu_add_contact">Add Contact</string>
-    <string name="menu_remove_contact">Delete Contact</string>
-    <string name="menu_block_contact">Block</string>
-    <string name="menu_contact_list">Contact List</string>
-    <string name="menu_start_chat">Send IM</string>
-    <string name="menu_view_profile">Buddy Info</string>
-    <string name="menu_end_conversation">End Conversation</string>
-    <string name="menu_switch_chats">Switch Chats</string>
-    <string name="menu_insert_smiley">Insert Emoticons</string>
-    <string name="sign_up">Get a new account</string>
-    <string name="check_save_password">For your security, if your phone is lost or stolen, go to the Web site on your computer and change your password.</string>
-    <string name="buddy_list_title">Contact List - <xliff:g id="username">%1$s</xliff:g></string>
-    <string name="label_username">Username:</string>
-    <string name="ongoing_conversation">Conversations (<xliff:g id="number">%1$d</xliff:g>)</string>
-    <string name="contact_profile_title">Contact Info</string>
-    <string name="presence_available">Available</string>
-    <string name="add_contact_title">Add Contact</string>
-    <string name="input_contact_label">Screen name of person you wish to add:</string>
-    <string name="invite_label">Add Buddy</string>
-
-    <string-array name="smiley_names">
-        <item>Happy</item>
-        <item>Sad</item>
-        <item>Winking</item>
-        <item>Tongue sticking out</item>
-        <item>Surprised</item>
-        <item>Kissing</item>
-        <item>Yelling</item>
-        <item>Cool</item>
-        <item>Money mouth</item>
-        <item>Foot in mouth</item>
-        <item>Embarrassed</item>
-        <item>Angel</item>
-        <item>Undecided</item>
-        <item>Crying</item>
-        <item>Lips are sealed</item>
-        <item>Laughing</item>
-        <item>Confused</item>
-    </string-array>
-
-    <string-array name="smiley_texts">
-        <item>:-)</item>
-        <item>:-(</item>
-        <item>;-)</item>
-        <item>:-P</item>
-        <item>=-O</item>
-        <item>:-*</item>
-        <item>:O</item>
-        <item>B-)</item>
-        <item>:-$</item>
-        <item>:-!</item>
-        <item>:-[</item>
-        <item>O:-)</item>
-        <item>:-\\</item>
-        <item>:\'(</item>
-        <item>:-X</item>
-        <item>:-D</item>
-        <item>o_O</item>
-    </string-array>
-</resources>
index eb7d0c9..5fe6cc0 100644 (file)
@@ -17,7 +17,7 @@
 package com.android.im.plugin.demo;
 
 import com.android.im.plugin.BrandingResourceIDs;
-import com.android.im.plugin.IImPlugin;
+import com.android.im.plugin.ImPlugin;
 import com.android.im.plugin.ImConfigNames;
 import com.android.im.plugin.ImpsConfigNames;
 
@@ -33,110 +33,105 @@ import java.util.Map;
  * Simple example of writing a plug-in for the IM application.
  *
  */
-public class DemoImPlugin extends Service {
+public class DemoImPlugin extends Service implements ImPlugin {
 
     @Override
     public IBinder onBind(Intent intent) {
-        return mBinder;
+        return null;
     }
 
-    /**
-     * The implementation of IImPlugin defined through AIDL.
-     */
-    private IBinder mBinder = new IImPlugin.Stub() {
-        public Map getProviderConfig() {
-            HashMap<String, String> config = new HashMap<String, String>();
-            // The protocol name MUST be IMPS now.
-            config.put(ImConfigNames.PROTOCOL_NAME, "IMPS");
-            config.put(ImpsConfigNames.HOST, "http://xxx.xxxx.xxx");
-            config.put(ImpsConfigNames.CLIENT_ID, "Jimmy");
-            config.put(ImpsConfigNames.DATA_CHANNEL, "HTTP");
-            config.put(ImpsConfigNames.DATA_ENCODING, "WBXML");
-            config.put(ImpsConfigNames.CIR_CHANNEL, "STCP");
-            config.put(ImpsConfigNames.CUSTOM_PRESENCE_MAPPING,
-                    "com.android.im.plugin.demo.DemoPresenceMapping");
-            return config;
-        }
+   public Map getProviderConfig() {
+       HashMap<String, String> config = new HashMap<String, String>();
+       // The protocol name MUST be IMPS now.
+       config.put(ImConfigNames.PROTOCOL_NAME, "IMPS");
+       config.put(ImpsConfigNames.HOST, "http://xxx.xxxx.xxx");
+       config.put(ImpsConfigNames.CLIENT_ID, "Jimmy");
+       config.put(ImpsConfigNames.DATA_CHANNEL, "HTTP");
+       config.put(ImpsConfigNames.DATA_ENCODING, "WBXML");
+       config.put(ImpsConfigNames.CIR_CHANNEL, "STCP");
+       config.put(ImpsConfigNames.CUSTOM_PRESENCE_MAPPING,
+               "com.android.im.plugin.demo.DemoPresenceMapping");
+       return config;
+   }
 
-        public Map getResourceMap() throws RemoteException {
-            HashMap<Integer, Integer> resMapping = new HashMap<Integer, Integer>();
-            resMapping.put(BrandingResourceIDs.DRAWABLE_LOGO, R.drawable.im_logo);
-            resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_ONLINE,
-                    android.R.drawable.presence_online);
-            resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_AWAY,
-                    android.R.drawable.presence_away);
-            resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_BUSY,
-                    android.R.drawable.presence_busy);
-            resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_INVISIBLE,
-                    android.R.drawable.presence_invisible);
-            resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_OFFLINE,
-                    android.R.drawable.presence_offline);
-            resMapping.put(BrandingResourceIDs.DRAWABLE_SPLASH_SCREEN,
-                    R.drawable.im_logo_splashscr);
-            resMapping.put(BrandingResourceIDs.DRAWABLE_READ_CHAT,
-                    R.drawable.chat);
-            resMapping.put(BrandingResourceIDs.DRAWABLE_UNREAD_CHAT,
-                    R.drawable.chat_new);
+   public Map getResourceMap() {
+       HashMap<Integer, Integer> resMapping = new HashMap<Integer, Integer>();
+/*       resMapping.put(BrandingResourceIDs.DRAWABLE_LOGO, R.drawable.im_logo);
+       resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_ONLINE,
+               android.R.drawable.presence_online);
+       resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_AWAY,
+               android.R.drawable.presence_away);
+       resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_BUSY,
+               android.R.drawable.presence_busy);
+       resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_INVISIBLE,
+               android.R.drawable.presence_invisible);
+       resMapping.put(BrandingResourceIDs.DRAWABLE_PRESENCE_OFFLINE,
+               android.R.drawable.presence_offline);
+       resMapping.put(BrandingResourceIDs.DRAWABLE_SPLASH_SCREEN,
+               R.drawable.im_logo_splashscr);
+       resMapping.put(BrandingResourceIDs.DRAWABLE_READ_CHAT,
+               R.drawable.chat);
+       resMapping.put(BrandingResourceIDs.DRAWABLE_UNREAD_CHAT,
+               R.drawable.chat_new);
 
-            resMapping.put(BrandingResourceIDs.STRING_BUDDY_LIST_TITLE,
-                    R.string.buddy_list_title);
-            resMapping.put(BrandingResourceIDs.STRING_ARRAY_SMILEY_NAMES,
-                    R.array.smiley_names);
-            resMapping.put(BrandingResourceIDs.STRING_ARRAY_SMILEY_TEXTS,
-                    R.array.smiley_texts);
-            resMapping.put(BrandingResourceIDs.STRING_PRESENCE_AVAILABLE,
-                    R.string.presence_available);
+       resMapping.put(BrandingResourceIDs.STRING_BUDDY_LIST_TITLE,
+               R.string.buddy_list_title);
+       resMapping.put(BrandingResourceIDs.STRING_ARRAY_SMILEY_NAMES,
+               R.array.smiley_names);
+       resMapping.put(BrandingResourceIDs.STRING_ARRAY_SMILEY_TEXTS,
+               R.array.smiley_texts);
+       resMapping.put(BrandingResourceIDs.STRING_PRESENCE_AVAILABLE,
+               R.string.presence_available);
 
-            resMapping.put(BrandingResourceIDs.STRING_LABEL_USERNAME,
-                    R.string.label_username);
-            resMapping.put(BrandingResourceIDs.STRING_ONGOING_CONVERSATION,
-                    R.string.ongoing_conversation);
-            resMapping.put(BrandingResourceIDs.STRING_ADD_CONTACT_TITLE,
-                    R.string.add_contact_title);
-            resMapping.put(BrandingResourceIDs.STRING_LABEL_INPUT_CONTACT,
-                    R.string.input_contact_label);
-            resMapping.put(BrandingResourceIDs.STRING_BUTTON_ADD_CONTACT,
-                    R.string.invite_label);
-            resMapping.put(BrandingResourceIDs.STRING_CONTACT_INFO_TITLE,
-                    R.string.contact_profile_title);
+       resMapping.put(BrandingResourceIDs.STRING_LABEL_USERNAME,
+               R.string.label_username);
+       resMapping.put(BrandingResourceIDs.STRING_ONGOING_CONVERSATION,
+               R.string.ongoing_conversation);
+       resMapping.put(BrandingResourceIDs.STRING_ADD_CONTACT_TITLE,
+               R.string.add_contact_title);
+       resMapping.put(BrandingResourceIDs.STRING_LABEL_INPUT_CONTACT,
+               R.string.input_contact_label);
+       resMapping.put(BrandingResourceIDs.STRING_BUTTON_ADD_CONTACT,
+               R.string.invite_label);
+       resMapping.put(BrandingResourceIDs.STRING_CONTACT_INFO_TITLE,
+               R.string.contact_profile_title);
 
-            resMapping.put(BrandingResourceIDs.STRING_MENU_ADD_CONTACT,
-                    R.string.menu_add_contact);
-            resMapping.put(BrandingResourceIDs.STRING_MENU_BLOCK_CONTACT,
-                    R.string.menu_block_contact);
-            resMapping.put(BrandingResourceIDs.STRING_MENU_CONTACT_LIST,
-                    R.string.menu_contact_list);
-            resMapping.put(BrandingResourceIDs.STRING_MENU_DELETE_CONTACT,
-                    R.string.menu_remove_contact);
-            resMapping.put(BrandingResourceIDs.STRING_MENU_END_CHAT,
-                    R.string.menu_end_conversation);
-            resMapping.put(BrandingResourceIDs.STRING_MENU_INSERT_SMILEY,
-                    R.string.menu_insert_smiley);
-            resMapping.put(BrandingResourceIDs.STRING_MENU_START_CHAT,
-                    R.string.menu_start_chat);
-            resMapping.put(BrandingResourceIDs.STRING_MENU_VIEW_PROFILE,
-                    R.string.menu_view_profile);
-            resMapping.put(BrandingResourceIDs.STRING_MENU_SWITCH_CHATS,
-                    R.string.menu_switch_chats);
+       resMapping.put(BrandingResourceIDs.STRING_MENU_ADD_CONTACT,
+               R.string.menu_add_contact);
+       resMapping.put(BrandingResourceIDs.STRING_MENU_BLOCK_CONTACT,
+               R.string.menu_block_contact);
+       resMapping.put(BrandingResourceIDs.STRING_MENU_CONTACT_LIST,
+               R.string.menu_contact_list);
+       resMapping.put(BrandingResourceIDs.STRING_MENU_DELETE_CONTACT,
+               R.string.menu_remove_contact);
+       resMapping.put(BrandingResourceIDs.STRING_MENU_END_CHAT,
+               R.string.menu_end_conversation);
+       resMapping.put(BrandingResourceIDs.STRING_MENU_INSERT_SMILEY,
+               R.string.menu_insert_smiley);
+       resMapping.put(BrandingResourceIDs.STRING_MENU_START_CHAT,
+               R.string.menu_start_chat);
+       resMapping.put(BrandingResourceIDs.STRING_MENU_VIEW_PROFILE,
+               R.string.menu_view_profile);
+       resMapping.put(BrandingResourceIDs.STRING_MENU_SWITCH_CHATS,
+               R.string.menu_switch_chats);
 
-            resMapping.put(BrandingResourceIDs.STRING_TOAST_CHECK_SAVE_PASSWORD,
-                    R.string.check_save_password);
-            resMapping.put(BrandingResourceIDs.STRING_LABEL_SIGN_UP,
-                    R.string.sign_up);
-            return resMapping;
-        }
+       resMapping.put(BrandingResourceIDs.STRING_TOAST_CHECK_SAVE_PASSWORD,
+               R.string.check_save_password);
+       resMapping.put(BrandingResourceIDs.STRING_LABEL_SIGN_UP,
+               R.string.sign_up);*/
+       return resMapping;
+   }
 
-        public int[] getSmileyIconIds() throws RemoteException {
-            return SMILEY_RES_IDS;
-        }
-    };
+   public int[] getSmileyIconIds() {
+       return SMILEY_RES_IDS;
+   }
 
     /**
      * An array of the smiley icon IDs. Note that the sequence of the array MUST
      * match the smiley texts and smiley names defined in strings.xml.
      */
     static final int[] SMILEY_RES_IDS = {
-        R.drawable.emo_im_happy,
+/*        R.drawable.emo_im_happy,
         R.drawable.emo_im_sad,
         R.drawable.emo_im_winking,
         R.drawable.emo_im_tongue_sticking_out,
@@ -152,7 +147,7 @@ public class DemoImPlugin extends Service {
         R.drawable.emo_im_crying,
         R.drawable.emo_im_lips_are_sealed,
         R.drawable.emo_im_laughing,
-        R.drawable.emo_im_wtf
+        R.drawable.emo_im_wtf */
     };
 
 }
index e8acb88..fc32984 100644 (file)
@@ -17,7 +17,7 @@
 package com.android.im.plugin.demo;
 
 import com.android.im.plugin.ImPluginConstants;
-import com.android.im.plugin.IPresenceMapping;
+import com.android.im.plugin.PresenceMapping;
 
 import java.util.Map;
 
@@ -25,7 +25,7 @@ import java.util.Map;
  * A simple implementation of PresenceMaping for the provider.
  *
  */
-public class DemoPresenceMapping extends IPresenceMapping.Stub {
+public class DemoPresenceMapping implements PresenceMapping {
 
     public int[] getSupportedPresenceStatus() {
         return new int[] {
index 97dd698..6708b9e 100644 (file)
@@ -17,7 +17,7 @@
 
 package com.android.im.app;
 
-import com.android.im.plugin.IImPlugin;
+import com.android.im.plugin.ImPlugin;
 import com.android.im.plugin.ImPluginInfo;
 import dalvik.system.PathClassLoader;
 
@@ -68,12 +68,11 @@ public class BrandingResources {
         // Load the plug-in directly from the apk instead of binding the service
         // and calling through the IPC binder API. It's more effective in this way
         // and we can avoid the async behaviors of binding service.
-        PathClassLoader classLoader = new PathClassLoader(pluginInfo.mSrcPath,
-                context.getClassLoader());
+        ClassLoader classLoader = context.getClassLoader();
         try {
             Class cls = classLoader.loadClass(pluginInfo.mClassName);
             Method m = cls.getMethod("onBind", Intent.class);
-            IImPlugin plugin = (IImPlugin)m.invoke(cls.newInstance(), new Object[]{null});
+            ImPlugin plugin = (ImPlugin)m.invoke(cls.newInstance(), new Object[]{null});
             mResMapping = plugin.getResourceMap();
             mSmileyIcons = plugin.getSmileyIconIds();
         } catch (ClassNotFoundException e) {
@@ -90,8 +89,6 @@ public class BrandingResources {
             Log.e(TAG, "Failed load the plugin resource map", e);
         } catch (InvocationTargetException e) {
             Log.e(TAG, "Failed load the plugin resource map", e);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed load the plugin resource map", e);
         }
     }
 
@@ -104,8 +101,14 @@ public class BrandingResources {
      */
     public BrandingResources(Context context, Map<Integer, Integer> resMapping,
             BrandingResources defaultRes) {
-        mPackageRes = context.getResources();
+        this(context.getResources(), resMapping, null, defaultRes);
+    }
+
+    public BrandingResources(Resources packageRes, Map<Integer, Integer> resMapping,
+            int[] smileyIcons, BrandingResources defaultRes) {
+        mPackageRes = packageRes;
         mResMapping = resMapping;
+        mSmileyIcons = smileyIcons;
         mDefaultRes = defaultRes;
     }
 
diff --git a/src/com/android/im/app/FrontDoorPlugin.java b/src/com/android/im/app/FrontDoorPlugin.java
deleted file mode 100644 (file)
index fedd45e..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright (C) 2008 Esmertec AG.
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.im.app;
-
-import com.android.im.plugin.ImConfigNames;
-import com.android.im.plugin.ImPluginConstants;
-
-import android.app.Service;
-import android.content.Intent;
-import android.content.ContentUris;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.im.IImPlugin;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.Bundle;
-import android.provider.Im;
-import android.util.Log;
-import android.text.TextUtils;
-import android.database.Cursor;
-import android.net.Uri;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.List;
-import java.util.ArrayList;
-import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
-
-import dalvik.system.PathClassLoader;
-
-
-public class FrontDoorPlugin extends Service {
-    private final static String TAG = ImApp.LOG_TAG;
-    private final static boolean LOCAL_DEBUG = false;
-
-    // database access constants for branding resource map cache table
-    private final static String[] BRANDING_RESOURCE_MAP_CACHE_PROJECTION = {
-        Im.BrandingResourceMapCache.PROVIDER_ID,
-        Im.BrandingResourceMapCache.APP_RES_ID,
-        Im.BrandingResourceMapCache.PLUGIN_RES_ID
-    };
-    private final static int BRANDING_RESOURCE_MAP_CACHE_PROVIDER_ID_COLUMN = 0;
-    private final static int BRANDING_RESOURCE_MAP_CACHE_APP_RES_ID_COLUMN = 1;
-    private final static int BRANDING_RESOURCE_MAP_CACHE_PLUGIN_RES_ID_COLUMN = 2;
-
-    private ArrayList<String> mProviderNames;
-    private HashMap<String, String> mPackageNames;
-    private HashMap<String, Map<Integer, Integer>> mBrandingResources;
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        // temporary mappings
-        HashMap<String, Long> providerNameToId = new HashMap<String, Long>();
-        HashMap<Long, String> providerIdToName = new HashMap<Long, String>();
-        HashMap<String, Class> classes = new HashMap<String, Class>();
-
-        loadThirdPartyPlugins(providerNameToId, providerIdToName, classes);
-        loadBrandingResources(providerNameToId, providerIdToName, classes);
-
-        return mBinder;
-    }
-
-    private void loadThirdPartyPlugins(
-            HashMap<String, Long> providerNameToId, HashMap<Long, String> providerIdToName,
-            HashMap<String, Class> classes) {
-        mProviderNames = new ArrayList<String>();
-        mPackageNames = new HashMap<String, String>();
-
-        PackageManager pm = getPackageManager();
-        List<ResolveInfo> plugins = pm.queryIntentServices(
-                new Intent(ImPluginConstants.PLUGIN_ACTION_NAME), PackageManager.GET_META_DATA);
-        int numPlugins = plugins.size();
-
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            log("loadThirdPartyPlugins: # plugins found: " + numPlugins);
-        }
-
-        if (numPlugins == 0) {
-            Log.e(TAG, "[IM.FrontDoorPlugin] no plugins found! bail...");
-            return;
-        }
-
-        for (ResolveInfo info : plugins) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) log("loadThirdPartyPlugins: found plugin " + info);
-
-            ServiceInfo serviceInfo = info.serviceInfo;
-            if (serviceInfo == null) {
-                Log.e(TAG, "[FrontDoorPlugin] loadThirdPartyPlugins: ignore bad plugin: " + info);
-                continue;
-            }
-
-            String providerName = null;
-            String providerFullName = null;
-            String signUpUrl = null;
-            Bundle metaData = serviceInfo.metaData;
-            if (metaData != null) {
-                providerName = metaData.getString(ImPluginConstants.METADATA_PROVIDER_NAME);
-                providerFullName =
-                    metaData.getString(ImPluginConstants.METADATA_PROVIDER_FULL_NAME);
-                signUpUrl = metaData.getString(ImPluginConstants.METADATA_SIGN_UP_URL);
-            }
-            if (TextUtils.isEmpty(providerName) || TextUtils.isEmpty(providerFullName)) {
-                Log.e(TAG, "[FrontDoorPlugin] Ignore bad IM plugin: " + info +
-                        ". Lack of required meta data");
-                continue;
-            }
-
-            mProviderNames.add(providerName);
-            mPackageNames.put(providerName, serviceInfo.packageName);
-
-            String className = serviceInfo.name;
-            String srcPath = serviceInfo.applicationInfo.sourceDir;
-            Class pluginClass = loadClass(className, srcPath);
-            if (pluginClass == null) {
-                Log.e(TAG, "[FrontDoorPlugin] Can not load package for plugin " + providerName);
-                continue;
-            }
-            classes.put(providerName, pluginClass);
-
-            Map<String, String> config = loadProviderConfigFromPlugin(pluginClass);
-            if (config == null) {
-                Log.e(TAG, "[FrontDoorPlugin] Can not load config for plugin " + providerName);
-                continue;
-            }
-            config.put(ImConfigNames.PLUGIN_PATH, srcPath);
-            config.put(ImConfigNames.PLUGIN_CLASS, className);
-
-            long providerId = DatabaseUtils.updateProviderDb(getContentResolver(),
-                    providerName, providerFullName, signUpUrl, config);
-            providerNameToId.put(providerName, providerId);
-            providerIdToName.put(providerId, providerName);
-        }
-    }
-
-    private void loadBrandingResources(
-            HashMap<String, Long> providerNameToId, HashMap<Long, String> providerIdToName,
-            HashMap<String, Class> classes) {
-        mBrandingResources = new HashMap<String, Map<Integer, Integer>>();
-
-        // first try load from cache
-        loadBrandingResourcesFromCache(providerIdToName);
-
-        // check and load any un-cached resources
-        final ArrayList<ContentValues> valuesList = new ArrayList<ContentValues>();
-        for (String provider : mProviderNames) {
-            long providerId = providerNameToId.get(provider);
-            if (!mBrandingResources.containsKey(provider)) {
-                Map<Integer, Integer> resMap = loadBrandingResource(classes.get(provider));
-                if (resMap != null) {
-                    mBrandingResources.put(provider, resMap);
-                    for (int appResId : resMap.keySet()) {
-                        int pluginResId = resMap.get(appResId);
-
-                        ContentValues values = new ContentValues();
-                        values.put(Im.BrandingResourceMapCache.PROVIDER_ID, providerId);
-                        values.put(Im.BrandingResourceMapCache.APP_RES_ID, appResId);
-                        values.put(Im.BrandingResourceMapCache.PLUGIN_RES_ID, pluginResId);
-
-                        valuesList.add(values);
-                    }
-                    Log.d(TAG, "Plugin " + provider + " not in cache, loaded and saved");
-                }
-            }
-        }
-
-        // save the changes to cache
-        if (valuesList.size() > 0) {
-            new Thread(new Runnable() {
-                public void run() {
-                    getContentResolver().bulkInsert(
-                            Im.BrandingResourceMapCache.CONTENT_URI,
-                            valuesList.toArray(new ContentValues[]{}));
-                }
-            }).start();
-        }
-    }
-
-    /**
-     * Try loading the branding resources from the database.
-     * @param providerIdToName a map between provider ID and name.
-     */
-    private void loadBrandingResourcesFromCache(HashMap<Long, String> providerIdToName) {
-        ContentResolver cr = getContentResolver();
-        Cursor c = cr.query(
-                Im.BrandingResourceMapCache.CONTENT_URI, /* URI */
-                BRANDING_RESOURCE_MAP_CACHE_PROJECTION,  /* projection */
-                null,                                    /* where */
-                null,                                    /* where args */
-                null                                     /* sort */);
-
-        if (c != null) {
-            try {
-                while (c.moveToNext()) {
-                    long providerId = c.getLong(BRANDING_RESOURCE_MAP_CACHE_PROVIDER_ID_COLUMN);
-                    String provider = providerIdToName.get(providerId);
-                    if (TextUtils.isEmpty(provider)) {
-                        Log.e(TAG, "Empty provider name in branding resource map cache table.");
-                        continue;
-                    }
-                    int appResId = c.getInt(BRANDING_RESOURCE_MAP_CACHE_APP_RES_ID_COLUMN);
-                    int pluginResId = c.getInt(BRANDING_RESOURCE_MAP_CACHE_PLUGIN_RES_ID_COLUMN);
-
-                    Map<Integer, Integer> resMap = mBrandingResources.get(provider);
-                    if (resMap == null) {
-                        resMap = new HashMap<Integer, Integer>();
-                        mBrandingResources.put(provider, resMap);
-                    }
-
-                    resMap.put(appResId, pluginResId);
-                }
-            } finally {
-                c.close();
-            }
-        } else {
-            Log.e(TAG, "Query of branding resource map cache table returns empty cursor"); 
-        }
-    }
-
-    /**
-     * Load branding resources from one plugin.
-     */
-    private Map<Integer, Integer> loadBrandingResource(Class cls) {
-        try {
-            Method m = cls.getMethod("getResourceMap");
-            // TODO: this would still cause a VM verifier exception to be thrown if.
-            // the landing page Android.mk and AndroidManifest.xml don't include use-library for
-            // "com.android.im.plugin". This is even with getCustomClassLoader() as the parent
-            // class loader.
-            return (Map)m.invoke(cls.newInstance(), new Object[]{});
-
-        } catch (IllegalAccessException e) {
-            Log.e(TAG, "Failed load the plugin resource map", e);
-        } catch (InstantiationException e) {
-            Log.e(TAG, "Failed load the plugin resource map", e);
-        } catch (SecurityException e) {
-            Log.e(TAG, "Failed load the plugin resource map", e);
-        } catch (NoSuchMethodException e) {
-            Log.e(TAG, "Failed load the plugin resource map", e);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Failed load the plugin resource map", e);
-        } catch (InvocationTargetException e) {
-            Log.e(TAG, "Failed load the plugin resource map", e);
-        }
-        return null;
-    }
-
-    /**
-     * Load plugin config.
-     */
-    private Map<String, String> loadProviderConfigFromPlugin(Class cls) {
-        try {
-            Method m = cls.getMethod("onBind", Intent.class);
-            com.android.im.plugin.IImPlugin plugin =
-                (com.android.im.plugin.IImPlugin)m.invoke(cls.newInstance(), new Object[]{null});
-            return plugin.getProviderConfig();
-        } catch (IllegalAccessException e) {
-            Log.e(TAG, "Could not create plugin instance", e);
-        } catch (InstantiationException e) {
-            Log.e(TAG, "Could not create plugin instance", e);
-        } catch (SecurityException e) {
-            Log.e(TAG, "Could not load config from the plugin", e);
-        } catch (NoSuchMethodException e) {
-            Log.e(TAG, "Could not load config from the plugin", e);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Could not load config from the plugin", e);
-        } catch (InvocationTargetException e) {
-            Log.e(TAG, "Could not load config from the plugin", e);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Could not load config from the plugin", e);
-        }
-        return null;
-    }
-
-    private Class loadClass(String className, String srcPath) {
-        PathClassLoader loader = new PathClassLoader(srcPath, getClassLoader());
-        try {
-            return loader.loadClass(className);
-        } catch (ClassNotFoundException e) {
-            Log.e(TAG, "Could not find plugin class", e);
-        }
-        return null;
-    }
-
-    private void log(String msg) {
-        Log.d(TAG, "[ImFrontDoor] " + msg);
-    }
-
-
-    /**
-     * The implementation of IImFrontDoorPlugin defined through AIDL.
-     */
-    private final IImPlugin.Stub mBinder = new IImPlugin.Stub() {
-
-        /**
-         * Notify the plugin the front door activity is created. This gives the plugin a chance to
-         * start its own servics, etc.
-         */
-        public void onStart() {
-        }
-
-        /**
-         * Notify the plugin the front door activity is stopping.
-         */
-        public void onStop() {
-        }
-
-        /**
-         * Sign in to the service for the account passed in.
-         */
-        public void signIn(long account) {
-            if (LOCAL_DEBUG) log("signIn for account " + account);
-
-            Intent intent = new Intent();
-            intent.setData(ContentUris.withAppendedId(Im.Account.CONTENT_URI, account));
-            intent.setClassName("com.android.im", "com.android.im.app.SigningInActivity");
-
-            startActivity(intent);
-        }
-
-        /**
-         * Sign out of the service for the account passed in.
-         */
-        public void signOut(long account) {
-            if (LOCAL_DEBUG) log("signOut for account " + account);
-            Intent intent = new Intent();
-            intent.setData(ContentUris.withAppendedId(Im.Account.CONTENT_URI, account));
-            intent.setClassName("com.android.im", "com.android.im.app.SignoutActivity");
-
-            startActivity(intent);
-        }
-
-        public String getResourcePackageNameForProvider(String providerName) {
-            return mPackageNames.get(providerName);
-        }
-
-        public Map getResourceMapForProvider(String providerName) throws RemoteException {
-            return mBrandingResources.get(providerName);
-        }
-
-        public List getSupportedProviders() {
-            return mProviderNames;
-        }
-    };
-
-}
index 86acc7c..1f23efd 100644 (file)
@@ -29,6 +29,7 @@ import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.net.ConnectivityManager;
@@ -51,6 +52,7 @@ import com.android.im.app.adapter.ConnectionListenerAdapter;
 import com.android.im.engine.ImConnection;
 import com.android.im.engine.ImErrorInfo;
 import com.android.im.plugin.BrandingResourceIDs;
+import com.android.im.plugin.ImPlugin;
 import com.android.im.plugin.ImPluginConstants;
 import com.android.im.plugin.ImPluginInfo;
 import com.android.im.service.ImServiceConstants;
@@ -59,6 +61,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 public class ImApp extends Application {
     public static final String LOG_TAG = "ImApp";
@@ -173,8 +176,6 @@ public class ImApp extends Application {
         super.onCreate();
         mBroadcaster = new Broadcaster();
         loadDefaultBrandingRes();
-        mBrandingResources = new HashMap<String, BrandingResources>();
-        loadThirdPartyResources();
     }
 
     @Override
@@ -294,7 +295,7 @@ public class ImApp extends Application {
         if (mProviders != null) {
             return;
         }
-        
+
         mProviders = new HashMap<Long, ProviderDef>();
         ContentResolver cr = getContentResolver();
 
@@ -401,40 +402,28 @@ public class ImApp extends Application {
     }
 
     private void loadThirdPartyResources() {
+        ImPluginHelper helper = ImPluginHelper.getInstance(this);
+        helper.loadAvaiablePlugins();
+        ArrayList<ImPlugin> pluginList = helper.getPluginObjects();
+        ArrayList<ImPluginInfo> infoList = helper.getPluginsInfo();
+        int N = pluginList.size();
         PackageManager pm = getPackageManager();
-        List<ResolveInfo> plugins = pm.queryIntentServices(
-                new Intent(ImPluginConstants.PLUGIN_ACTION_NAME), PackageManager.GET_META_DATA);
-        for (ResolveInfo info : plugins) {
-            Log.d(LOG_TAG, "Found plugin " + info);
-
-            ServiceInfo serviceInfo = info.serviceInfo;
-            if (serviceInfo == null) {
-                Log.e(LOG_TAG, "Ignore bad IM plugin: " + info);
-                continue;
-            }
-            String providerName = null;
-            String providerFullName = null;
-            Bundle metaData = serviceInfo.metaData;
-            if (metaData != null) {
-                providerName = metaData.getString(
-                        ImPluginConstants.METADATA_PROVIDER_NAME);
-                providerFullName = metaData.getString(
-                        ImPluginConstants.METADATA_PROVIDER_FULL_NAME);
-            }
-            if (TextUtils.isEmpty(providerName)
-                    || TextUtils.isEmpty(providerFullName)) {
-                Log.e(LOG_TAG, "Ignore bad IM plugin: " + info
-                        + ". Lack of required meta data");
-                continue;
-            }
+        for (int i = 0; i < N; i++) {
+            ImPlugin plugin = pluginList.get(i);
+            ImPluginInfo pluginInfo = infoList.get(i);
+
+            try {
+                Resources packageRes = pm.getResourcesForApplication(pluginInfo.mPackageName);
 
-            ImPluginInfo pluginInfo = new ImPluginInfo(providerName,
-                    serviceInfo.packageName, serviceInfo.name,
-                    serviceInfo.applicationInfo.sourceDir);
+                Map<Integer, Integer> resMap = plugin.getResourceMap();
+                int[] smileyIcons = plugin.getSmileyIconIds();
 
-            BrandingResources res = new BrandingResources(this, pluginInfo,
-                    mDefaultBrandingResources);
-            mBrandingResources.put(providerName, res);
+                BrandingResources res = new BrandingResources(packageRes, resMap,
+                        smileyIcons, mDefaultBrandingResources);
+                mBrandingResources.put(pluginInfo.mProviderName, res);
+            } catch (NameNotFoundException e) {
+                Log.e(LOG_TAG, "Failed to load third party resources.", e);
+            }
         }
     }
 
@@ -465,6 +454,10 @@ public class ImApp extends Application {
         if (provider == null) {
             return mDefaultBrandingResources;
         }
+        if (mBrandingResources == null) {
+            mBrandingResources = new HashMap<String, BrandingResources>();
+            loadThirdPartyResources();
+        }
         BrandingResources res = mBrandingResources.get(provider.mName);
         return res == null ? mDefaultBrandingResources : res;
     }
@@ -670,6 +663,9 @@ public class ImApp extends Application {
 
                 case ImConnection.LOGGING_OUT:
                     what = EVENT_CONNECTION_LOGGING_OUT;
+                    synchronized (mConnections) {
+                        mConnections.remove(providerId);
+                    }
                     break;
 
                 case ImConnection.DISCONNECTED:
diff --git a/src/com/android/im/app/ImPluginHelper.java b/src/com/android/im/app/ImPluginHelper.java
new file mode 100644 (file)
index 0000000..f557493
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2009 Myriad Group AG.
+ * 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.im.app;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteFullException;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Im;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.im.plugin.ImConfigNames;
+import com.android.im.plugin.ImPlugin;
+import com.android.im.plugin.ImPluginConstants;
+import com.android.im.plugin.ImPluginInfo;
+
+public class ImPluginHelper {
+
+    private static final String TAG = "ImPluginUtils";
+
+    private Context mContext;
+    private ArrayList<ImPluginInfo> mPluginsInfo;
+    private ArrayList<ImPlugin> mPluginObjects;
+    private boolean mLoaded;
+
+    private static ImPluginHelper sInstance;
+    public static ImPluginHelper getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new ImPluginHelper(context);
+        }
+        return sInstance;
+    }
+
+    private ImPluginHelper(Context context) {
+        mContext = context;
+        mPluginsInfo = new ArrayList<ImPluginInfo>();
+        mPluginObjects = new ArrayList<ImPlugin>();
+    }
+
+    public ArrayList<ImPluginInfo> getPluginsInfo() {
+        if (!mLoaded) {
+            loadAvaiablePlugins();
+        }
+        return mPluginsInfo;
+    }
+
+    public ArrayList<ImPlugin> getPluginObjects() {
+        if (!mLoaded) {
+            loadAvaiablePlugins();
+        }
+        return mPluginObjects;
+    }
+
+    public void loadAvaiablePlugins() {
+        if (mLoaded) {
+            return;
+        }
+
+        PackageManager pm = mContext.getPackageManager();
+        List<ResolveInfo> plugins = pm.queryIntentServices(
+                new Intent(ImPluginConstants.PLUGIN_ACTION_NAME), PackageManager.GET_META_DATA);
+        for (ResolveInfo info : plugins) {
+            Log.d(TAG, "Found plugin " + info);
+
+            ServiceInfo serviceInfo = info.serviceInfo;
+            if (serviceInfo == null) {
+                Log.e(TAG, "Ignore bad IM plugin: " + info);
+                continue;
+            }
+            String providerName = null;
+            String providerFullName = null;
+            String signUpUrl = null;
+            Bundle metaData = serviceInfo.metaData;
+            if (metaData != null) {
+                providerName = metaData.getString(ImPluginConstants.METADATA_PROVIDER_NAME);
+                providerFullName = metaData.getString(ImPluginConstants.METADATA_PROVIDER_FULL_NAME);
+                signUpUrl = metaData.getString(ImPluginConstants.METADATA_SIGN_UP_URL);
+            }
+            if (TextUtils.isEmpty(providerName) || TextUtils.isEmpty(providerFullName)) {
+                Log.e(TAG, "Ignore bad IM plugin: " + info + ". Lack of required meta data");
+                continue;
+            }
+
+            if (isPluginDuplicated(providerName)) {
+                Log.e(TAG, "Ignore duplicated IM plugin: " + info);
+                continue;
+            }
+
+            if (!serviceInfo.packageName.equals(mContext.getPackageName())) {
+                Log.e(TAG, "Ignore plugin in package: " + serviceInfo.packageName);
+                continue;
+            }
+            ImPluginInfo pluginInfo = new ImPluginInfo(providerName, serviceInfo.packageName,
+                    serviceInfo.name, serviceInfo.applicationInfo.sourceDir);
+
+            ImPlugin plugin = loadPlugin(pluginInfo);
+            if (plugin == null) {
+                Log.e(TAG, "Ignore bad IM plugin");
+                continue;
+            }
+
+            try {
+                updateProviderDb(plugin, pluginInfo,providerFullName, signUpUrl);
+            } catch (SQLiteFullException e) {
+                Log.e(TAG, "Storage full", e);
+                return;
+            }
+            mPluginsInfo.add(pluginInfo);
+            mPluginObjects.add(plugin);
+        }
+        mLoaded = true;
+    }
+
+    private boolean isPluginDuplicated(String providerName) {
+        for (ImPluginInfo plugin : mPluginsInfo) {
+            if (plugin.mProviderName.equals(providerName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private ImPlugin loadPlugin(ImPluginInfo pluginInfo) {
+        // XXX Load the plug-in implementation directly from the apk rather than
+        // binding to the service and call through IPC Binder API. This is much
+        // more effective since we don't need to start the service in other
+        // process. We can not run the plug-in service in the same process as a
+        // local service because that the interface is defined in a shared
+        // library in order to compile the plug-in separately. In this case, the
+        // interface will be loaded by two class loader separately and a
+        // ClassCastException will be thrown if we cast the binder to the
+        // interface.
+        ClassLoader loader = mContext.getClassLoader();
+        try {
+            Class<?> cls = loader.loadClass(pluginInfo.mClassName);
+            return (ImPlugin) cls.newInstance();
+        } catch (ClassNotFoundException e) {
+            Log.e(TAG, "Could not find plugin class", e);
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Could not create plugin instance", e);
+        } catch (InstantiationException e) {
+            Log.e(TAG, "Could not create plugin instance", e);
+        } catch (SecurityException e) {
+            Log.e(TAG, "Could not load plugin", e);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Could not load plugin", e);
+        }
+        return null;
+    }
+
+    private long updateProviderDb(ImPlugin plugin, ImPluginInfo info,
+            String providerFullName, String signUpUrl) {
+        Map<String, String> config = loadConfiguration(plugin, info);
+        if (config == null) {
+            return 0;
+        }
+
+        long providerId = 0;
+        ContentResolver cr = mContext.getContentResolver();
+        String where = Im.Provider.NAME + "=?";
+        String[] selectionArgs = new String[]{info.mProviderName};
+        Cursor c = cr.query(Im.Provider.CONTENT_URI,
+                null /* projection */,
+                where,
+                selectionArgs,
+                null /* sort order */);
+
+        boolean pluginChanged;
+        try {
+            if (c.moveToFirst()) {
+                providerId = c.getLong(c.getColumnIndexOrThrow(Im.Provider._ID));
+                pluginChanged = isPluginChanged(cr, providerId, config);
+                if (pluginChanged) {
+                    // Update the full name, signup url and category each time when the plugin change
+                    // instead of specific version change because this is called only once.
+                    // It's ok to update them even the values are not changed.
+                    // Note that we don't update the provider name because it's used as
+                    // identifier at some place and the plugin should never change it.
+                    ContentValues values = new ContentValues(3);
+                    values.put(Im.Provider.FULLNAME, providerFullName);
+                    values.put(Im.Provider.SIGNUP_URL, signUpUrl);
+                    values.put(Im.Provider.CATEGORY, ImApp.IMPS_CATEGORY);
+                    Uri uri = ContentUris.withAppendedId(Im.Provider.CONTENT_URI, providerId);
+                    cr.update(uri, values, null, null);
+                }
+            } else {
+                ContentValues values = new ContentValues(3);
+                values.put(Im.Provider.NAME, info.mProviderName);
+                values.put(Im.Provider.FULLNAME, providerFullName);
+                values.put(Im.Provider.CATEGORY, ImApp.IMPS_CATEGORY);
+                values.put(Im.Provider.SIGNUP_URL, signUpUrl);
+
+                Uri result = cr.insert(Im.Provider.CONTENT_URI, values);
+                providerId = ContentUris.parseId(result);
+                pluginChanged = true;
+            }
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+
+        if (pluginChanged) {
+            // Remove all the old settings
+            cr.delete(ContentUris.withAppendedId(
+                    Im.ProviderSettings.CONTENT_URI, providerId),
+                    null, /*where*/
+                    null /*selectionArgs*/);
+
+            ContentValues[] settingValues = new ContentValues[config.size()];
+
+            int index = 0;
+            for (Map.Entry<String, String> entry : config.entrySet()) {
+                ContentValues settingValue = new ContentValues();
+                settingValue.put(Im.ProviderSettings.PROVIDER, providerId);
+                settingValue.put(Im.ProviderSettings.NAME, entry.getKey());
+                settingValue.put(Im.ProviderSettings.VALUE, entry.getValue());
+                settingValues[index++] = settingValue;
+            }
+            cr.bulkInsert(Im.ProviderSettings.CONTENT_URI, settingValues);
+        }
+
+        return providerId;
+    }
+
+    @SuppressWarnings("unchecked")
+    private Map<String, String> loadConfiguration(ImPlugin plugin,
+            ImPluginInfo info) {
+        Map<String, String> config = null;
+
+            config = plugin.getProviderConfig();
+
+        if (config != null) {
+            config.put(ImConfigNames.PLUGIN_PATH, info.mSrcPath);
+            config.put(ImConfigNames.PLUGIN_CLASS, info.mClassName);
+        }
+        return config;
+    }
+
+    private boolean isPluginChanged(ContentResolver cr, long providerId,
+            Map<String, String> config) {
+        String origVersion = Im.ProviderSettings.getStringValue(cr, providerId,
+                ImConfigNames.PLUGIN_VERSION);
+
+        if (origVersion == null) {
+            return true;
+        }
+        String newVersion = config.get(ImConfigNames.PLUGIN_VERSION);
+        return !origVersion.equals(newVersion);
+    }
+}
diff --git a/src/com/android/im/app/LandingPage.java b/src/com/android/im/app/LandingPage.java
new file mode 100644 (file)
index 0000000..cdbea1e
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.im.app;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ListActivity;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.RemoteException;
+import android.provider.Im;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.widget.AdapterView;
+import android.widget.CursorAdapter;
+import android.widget.ListView;
+
+import com.android.im.IImConnection;
+import com.android.im.R;
+import com.android.im.plugin.BrandingResourceIDs;
+
+public class LandingPage extends ListActivity implements View.OnCreateContextMenuListener {
+    private static final String TAG = ImApp.LOG_TAG;
+
+    private static final int ID_SIGN_IN = Menu.FIRST + 1;
+    private static final int ID_SIGN_OUT = Menu.FIRST + 2;
+    private static final int ID_EDIT_ACCOUNT = Menu.FIRST + 3;
+    private static final int ID_REMOVE_ACCOUNT = Menu.FIRST + 4;
+    private static final int ID_SIGN_OUT_ALL = Menu.FIRST + 5;
+    private static final int ID_ADD_ACCOUNT = Menu.FIRST + 6;
+    private static final int ID_VIEW_CONTACT_LIST = Menu.FIRST + 7;
+    private static final int ID_SETTINGS = Menu.FIRST + 8;
+
+    private ProviderAdapter mAdapter;
+    private Cursor mProviderCursor;
+    private ImApp mApp;
+    private SimpleAlertHandler mHandler;
+
+    private static final String[] PROVIDER_PROJECTION = {
+            Im.Provider._ID,
+            Im.Provider.NAME,
+            Im.Provider.FULLNAME,
+            Im.Provider.CATEGORY,
+            Im.Provider.ACTIVE_ACCOUNT_ID,
+            Im.Provider.ACTIVE_ACCOUNT_USERNAME,
+            Im.Provider.ACTIVE_ACCOUNT_PW,
+            Im.Provider.ACTIVE_ACCOUNT_LOCKED,
+            Im.Provider.ACTIVE_ACCOUNT_KEEP_SIGNED_IN,
+            Im.Provider.ACCOUNT_PRESENCE_STATUS,
+            Im.Provider.ACCOUNT_CONNECTION_STATUS,
+    };
+
+    static final int PROVIDER_ID_COLUMN = 0;
+    static final int PROVIDER_NAME_COLUMN = 1;
+    static final int PROVIDER_FULLNAME_COLUMN = 2;
+    static final int PROVIDER_CATEGORY_COLUMN = 3;
+    static final int ACTIVE_ACCOUNT_ID_COLUMN = 4;
+    static final int ACTIVE_ACCOUNT_USERNAME_COLUMN = 5;
+    static final int ACTIVE_ACCOUNT_PW_COLUMN = 6;
+    static final int ACTIVE_ACCOUNT_LOCKED = 7;
+    static final int ACTIVE_ACCOUNT_KEEP_SIGNED_IN = 8;
+    static final int ACCOUNT_PRESENCE_STATUS = 9;
+    static final int ACCOUNT_CONNECTION_STATUS = 10;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setTitle(R.string.landing_page_title);
+
+        mApp = ImApp.getApplication(this);
+        mHandler = new MyHandler(this);
+
+        ImPluginHelper.getInstance(this).loadAvaiablePlugins();
+
+        mProviderCursor = managedQuery(Im.Provider.CONTENT_URI_WITH_ACCOUNT,
+                PROVIDER_PROJECTION,
+                null /* selection */,
+                null /* selection args */,
+                Im.Provider.DEFAULT_SORT_ORDER);
+        mAdapter = new ProviderAdapter(this, mProviderCursor);
+        setListAdapter(mAdapter);
+
+        registerForContextMenu(getListView());
+    }
+
+
+    @Override
+    protected void onPause() {
+        mHandler.unregisterForBroadcastEvents();
+
+        super.onPause();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        mHandler.registerForBroadcastEvents();
+    }
+
+    private void signIn(long accountId) {
+        if (accountId == 0) {
+            Log.w(TAG, "signIn: account id is 0, bail");
+            return;
+        }
+
+        boolean isAccountEditible = mProviderCursor.getInt(ACTIVE_ACCOUNT_LOCKED) == 0;
+        if (isAccountEditible && mProviderCursor.isNull(ACTIVE_ACCOUNT_PW_COLUMN)) {
+            // no password, edit the account
+            if (Log.isLoggable(TAG, Log.DEBUG)) log("no pw for account " + accountId);
+            Intent intent = getEditAccountIntent();
+            startActivity(intent);
+            return;
+        }
+
+        Intent intent = new Intent(this, SigningInActivity.class);
+        intent.setData(ContentUris.withAppendedId(Im.Account.CONTENT_URI, accountId));
+        startActivity(intent);
+    }
+
+    boolean isSigningIn(Cursor cursor) {
+        int connectionStatus = cursor.getInt(ACCOUNT_CONNECTION_STATUS);
+        return connectionStatus == Im.ConnectionStatus.CONNECTING;
+    }
+
+    private boolean isSignedIn(Cursor cursor) {
+        int connectionStatus = cursor.getInt(ACCOUNT_CONNECTION_STATUS);
+        return connectionStatus == Im.ConnectionStatus.ONLINE;
+    }
+
+    private boolean allAccountsSignedOut() {
+        if(!mProviderCursor.moveToFirst()) {
+            return false;
+        }
+        do {
+            if (isSignedIn(mProviderCursor)) {
+                return false;
+            }
+        } while (mProviderCursor.moveToNext()) ;
+
+        return true;
+    }
+
+    private void signoutAll() {
+        DialogInterface.OnClickListener confirmListener
+                = new DialogInterface.OnClickListener(){
+            public void onClick(DialogInterface dialog, int whichButton) {
+                do {
+                    long accountId = mProviderCursor.getLong(ACTIVE_ACCOUNT_ID_COLUMN);
+                    signOut(accountId);
+                } while (mProviderCursor.moveToNext()) ;
+            }
+        };
+
+        new AlertDialog.Builder(this)
+            .setTitle(R.string.confirm)
+            .setMessage(R.string.signout_all_confirm_message)
+            .setPositiveButton(R.string.yes, confirmListener) // default button
+            .setNegativeButton(R.string.no, null)
+            .setCancelable(true)
+            .show();
+    }
+
+    private void signOut(long accountId) {
+        if (accountId == 0) {
+            Log.w(TAG, "signOut: account id is 0, bail");
+            return;
+        }
+
+        try {
+            IImConnection conn = mApp.getConnectionByAccount(accountId);
+            if (conn != null) {
+                conn.logout();
+            }
+        } catch (RemoteException ex) {
+            Log.e(TAG, "signOut failed", ex);
+        }
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        super.onPrepareOptionsMenu(menu);
+        menu.findItem(ID_SIGN_OUT_ALL).setVisible(!allAccountsSignedOut());
+        return true;
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        menu.add(0, ID_SIGN_OUT_ALL, 0, R.string.menu_sign_out_all)
+                .setIcon(android.R.drawable.ic_menu_close_clear_cancel);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case ID_SIGN_OUT_ALL:
+                signoutAll();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+        AdapterView.AdapterContextMenuInfo info;
+        try {
+            info = (AdapterView.AdapterContextMenuInfo) menuInfo;
+        } catch (ClassCastException e) {
+            Log.e(TAG, "bad menuInfo", e);
+            return;
+        }
+
+        Cursor providerCursor = (Cursor) getListAdapter().getItem(info.position);
+        menu.setHeaderTitle(providerCursor.getString(PROVIDER_FULLNAME_COLUMN));
+
+        if (providerCursor.isNull(ACTIVE_ACCOUNT_ID_COLUMN)) {
+            menu.add(0, ID_ADD_ACCOUNT, 0, R.string.menu_add_account);
+            return;
+        }
+
+        long providerId = providerCursor.getLong(PROVIDER_ID_COLUMN);
+        boolean isLoggingIn = isSigningIn(providerCursor);
+        boolean isLoggedIn = isSignedIn(providerCursor);
+
+        BrandingResources brandingRes = mApp.getBrandingResource(providerId);
+        if (!isLoggedIn) {
+            menu.add(0, ID_SIGN_IN, 0, R.string.sign_in).setIcon(com.android.internal.R.drawable.ic_menu_login);
+        } else {
+            menu.add(0, ID_VIEW_CONTACT_LIST, 0,
+                    brandingRes.getString(BrandingResourceIDs.STRING_MENU_CONTACT_LIST));
+            menu.add(0, ID_SIGN_OUT, 0, R.string.menu_sign_out)
+                .setIcon(android.R.drawable.ic_menu_close_clear_cancel);
+        }
+
+        boolean isAccountEditible = providerCursor.getInt(ACTIVE_ACCOUNT_LOCKED) == 0;
+        if (isAccountEditible && !isLoggingIn && !isLoggedIn) {
+            menu.add(0, ID_EDIT_ACCOUNT, 0, R.string.menu_edit_account)
+                .setIcon(android.R.drawable.ic_menu_edit);
+            menu.add(0, ID_REMOVE_ACCOUNT, 0, R.string.menu_remove_account)
+                .setIcon(android.R.drawable.ic_menu_delete);
+        }
+
+        // always add a settings menu item
+        menu.add(0, ID_SETTINGS, 0, R.string.menu_settings);
+    }
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item) {
+        AdapterView.AdapterContextMenuInfo info;
+        try {
+            info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
+        } catch (ClassCastException e) {
+            Log.e(TAG, "bad menuInfo", e);
+            return false;
+        }
+        long providerId = info.id;
+        Cursor providerCursor = (Cursor) getListAdapter().getItem(info.position);
+        long accountId = providerCursor.getLong(ACTIVE_ACCOUNT_ID_COLUMN);
+
+        switch (item.getItemId()) {
+            case ID_EDIT_ACCOUNT:
+            {
+                startActivity(getEditAccountIntent());
+                return true;
+            }
+
+            case ID_REMOVE_ACCOUNT:
+            {
+                Uri accountUri = ContentUris.withAppendedId(Im.Account.CONTENT_URI, accountId);
+                getContentResolver().delete(accountUri, null, null);
+                // Requery the cursor to force refreshing screen
+                providerCursor.requery();
+                return true;
+            }
+
+            case ID_VIEW_CONTACT_LIST:
+            {
+                Intent intent = getViewContactsIntent();
+                startActivity(intent);
+                return true;
+            }
+            case ID_ADD_ACCOUNT:
+            {
+                startActivity(getCreateAccountIntent());
+                return true;
+            }
+
+            case ID_SIGN_IN:
+            {
+                signIn(accountId);
+                return true;
+            }
+
+            case ID_SIGN_OUT:
+            {
+                // TODO: progress bar
+                signOut(accountId);
+                return true;
+            }
+
+            case ID_SETTINGS:
+            {
+                Intent intent = new Intent(Intent.ACTION_VIEW, Im.ProviderSettings.CONTENT_URI);
+                intent.addCategory(getProviderCategory(providerCursor));
+                intent.putExtra("providerId", providerId);
+                startActivity(intent);
+                return true;
+            }
+
+        }
+
+        return false;
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        Intent intent = null;
+        mProviderCursor.moveToPosition(position);
+
+        if (mProviderCursor.isNull(ACTIVE_ACCOUNT_ID_COLUMN)) {
+            // add account
+            intent = getCreateAccountIntent();
+        } else {
+            int state = mProviderCursor.getInt(ACCOUNT_CONNECTION_STATUS);
+            long accountId = mProviderCursor.getLong(ACTIVE_ACCOUNT_ID_COLUMN);
+
+            if (state == Im.ConnectionStatus.OFFLINE) {
+                boolean isKeepSignedIn = mProviderCursor.getInt(ACTIVE_ACCOUNT_KEEP_SIGNED_IN) != 0;
+                boolean isAccountEditible = mProviderCursor.getInt(ACTIVE_ACCOUNT_LOCKED) == 0;
+                if (isKeepSignedIn) {
+                    signIn(accountId);
+                } else if(isAccountEditible) {
+                    intent = getEditAccountIntent();
+                }
+            } else if (state == Im.ConnectionStatus.CONNECTING) {
+                signIn(accountId);
+            } else {
+                intent = getViewContactsIntent();
+            }
+        }
+
+        if (intent != null) {
+            startActivity(intent);
+        }
+    }
+
+    Intent getCreateAccountIntent() {
+        Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_INSERT);
+
+        long providerId = mProviderCursor.getLong(PROVIDER_ID_COLUMN);
+        intent.setData(ContentUris.withAppendedId(Im.Provider.CONTENT_URI, providerId));
+        intent.addCategory(getProviderCategory(mProviderCursor));
+        return intent;
+    }
+
+    Intent getEditAccountIntent() {
+        Intent intent = new Intent(Intent.ACTION_EDIT,
+                ContentUris.withAppendedId(Im.Account.CONTENT_URI,
+                        mProviderCursor.getLong(ACTIVE_ACCOUNT_ID_COLUMN)));
+        intent.addCategory(getProviderCategory(mProviderCursor));
+        return intent;
+    }
+
+    Intent getViewContactsIntent() {
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.setData(Im.Contacts.CONTENT_URI);
+        intent.addCategory(getProviderCategory(mProviderCursor));
+        intent.putExtra("accountId", mProviderCursor.getLong(ACTIVE_ACCOUNT_ID_COLUMN));
+        return intent;
+    }
+
+    private String getProviderCategory(Cursor cursor) {
+        return cursor.getString(PROVIDER_CATEGORY_COLUMN);
+    }
+
+    static void log(String msg) {
+        Log.d(TAG, "[LandingPage]" + msg);
+    }
+
+    private class ProviderListItemFactory implements LayoutInflater.Factory {
+        public View onCreateView(String name, Context context, AttributeSet attrs) {
+            if (name != null && name.equals(ProviderListItem.class.getName())) {
+                return new ProviderListItem(context, LandingPage.this);
+            }
+            return null;
+        }
+    }
+
+    private final class ProviderAdapter extends CursorAdapter {
+        private LayoutInflater mInflater;
+
+        public ProviderAdapter(Context context, Cursor c) {
+            super(context, c);
+            mInflater = LayoutInflater.from(context).cloneInContext(context);
+            mInflater.setFactory(new ProviderListItemFactory());
+        }
+
+        @Override
+        public View newView(Context context, Cursor cursor, ViewGroup parent) {
+            // create a custom view, so we can manage it ourselves. Mainly, we want to
+            // initialize the widget views (by calling getViewById()) in newView() instead of in
+            // bindView(), which can be called more often.
+            ProviderListItem view = (ProviderListItem) mInflater.inflate(
+                    R.layout.account_view, parent, false);
+            view.init(cursor);
+            return view;
+        }
+
+        @Override
+        public void bindView(View view, Context context, Cursor cursor) {
+            ((ProviderListItem) view).bindView(cursor);
+        }
+    }
+
+    private final static class MyHandler extends SimpleAlertHandler {
+
+        public MyHandler(Activity activity) {
+            super(activity);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == ImApp.EVENT_CONNECTION_DISCONNECTED) {
+                promptDisconnectedEvent(msg);
+            }
+            super.handleMessage(msg);
+        }
+    }
+}
diff --git a/src/com/android/im/app/ProviderListItem.java b/src/com/android/im/app/ProviderListItem.java
new file mode 100644 (file)
index 0000000..882a424
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2009 Myriad Group AG
+ * 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.im.app;
+
+import com.android.im.R;
+
+import android.graphics.drawable.Drawable;
+import android.widget.LinearLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.im.BrandingResourceIDs;
+import android.content.res.ColorStateList;
+import android.view.View;
+import android.provider.Im;
+import android.util.Log;
+
+public class ProviderListItem extends LinearLayout {
+    private static final String TAG = "IM";
+    private static final boolean LOCAL_DEBUG = false;
+
+    private LandingPage mActivity;
+    private ImageView mProviderIcon;
+    private ImageView mStatusIcon;
+    private TextView mProviderName;
+    private TextView mLoginName;
+    private TextView mChatView;
+    private View mUnderBubble;
+    private Drawable mBubbleDrawable, mDefaultBackground;
+
+    private int mProviderIdColumn;
+    private int mProviderFullnameColumn;
+    private int mActiveAccountIdColumn;
+    private int mActiveAccountUserNameColumn;
+    private int mAccountPresenceStatusColumn;
+    private int mAccountConnectionStatusColumn;
+
+    private ColorStateList mProviderNameColors;
+    private ColorStateList mLoginNameColors;
+    private ColorStateList mChatViewColors;
+
+    public ProviderListItem(Context context, LandingPage activity) {
+        super(context);
+        mActivity = activity;
+    }
+
+    public void init(Cursor c) {
+        mProviderIcon = (ImageView) findViewById(R.id.providerIcon);
+        mStatusIcon = (ImageView) findViewById(R.id.statusIcon);
+        mProviderName = (TextView) findViewById(R.id.providerName);
+        mLoginName = (TextView) findViewById(R.id.loginName);
+        mChatView = (TextView) findViewById(R.id.conversations);
+        mUnderBubble = findViewById(R.id.underBubble);
+        mBubbleDrawable = getResources().getDrawable(R.drawable.bubble);
+        mDefaultBackground = getResources().getDrawable(R.drawable.default_background);
+
+        mProviderIdColumn = c.getColumnIndexOrThrow(Im.Provider._ID);
+        mProviderFullnameColumn = c.getColumnIndexOrThrow(Im.Provider.FULLNAME);
+        mActiveAccountIdColumn = c.getColumnIndexOrThrow(
+                Im.Provider.ACTIVE_ACCOUNT_ID);
+        mActiveAccountUserNameColumn = c.getColumnIndexOrThrow(
+                Im.Provider.ACTIVE_ACCOUNT_USERNAME);
+        mAccountPresenceStatusColumn = c.getColumnIndexOrThrow(
+                Im.Provider.ACCOUNT_PRESENCE_STATUS);
+        mAccountConnectionStatusColumn = c.getColumnIndexOrThrow(
+                Im.Provider.ACCOUNT_CONNECTION_STATUS);
+
+        mProviderNameColors = mProviderName.getTextColors();
+        mLoginNameColors = mLoginName.getTextColors();
+        mChatViewColors = mChatView.getTextColors();
+    }
+
+    public void bindView(Cursor cursor) {
+        Resources r = getResources();
+        ImageView providerIcon = mProviderIcon;
+        ImageView statusIcon = mStatusIcon;
+        TextView providerName = mProviderName;
+        TextView loginName = mLoginName;
+        TextView chatView = mChatView;
+
+        int providerId = cursor.getInt(mProviderIdColumn);
+        String providerDisplayName = cursor.getString(mProviderFullnameColumn);
+
+        ImApp app = ImApp.getApplication(mActivity);
+        BrandingResources brandingRes = app.getBrandingResource(providerId);
+        providerIcon.setImageDrawable(
+                brandingRes.getDrawable(BrandingResourceIDs.DRAWABLE_LOGO));
+
+        mUnderBubble.setBackgroundDrawable(mDefaultBackground);
+        statusIcon.setVisibility(View.GONE);
+
+        providerName.setTextColor(mProviderNameColors);
+        loginName.setTextColor(mLoginNameColors);
+        chatView.setTextColor(mChatViewColors);
+
+        if (!cursor.isNull(mActiveAccountIdColumn)) {
+            mLoginName.setVisibility(View.VISIBLE);
+            providerName.setVisibility(View.VISIBLE);
+            providerName.setText(providerDisplayName);
+
+            long accountId = cursor.getLong(mActiveAccountIdColumn);
+            int connectionStatus = cursor.getInt(mAccountConnectionStatusColumn);
+
+            String secondRowText;
+
+            chatView.setVisibility(View.GONE);
+
+            switch (connectionStatus) {
+                case Im.ConnectionStatus.CONNECTING:
+                    secondRowText = r.getString(R.string.signing_in_wait);
+                    break;
+
+                case Im.ConnectionStatus.ONLINE:
+                    int presenceIconId = getPresenceIconId(cursor);
+                    statusIcon.setImageDrawable(
+                            brandingRes.getDrawable(presenceIconId));
+                    statusIcon.setVisibility(View.VISIBLE);
+                    ContentResolver cr = mActivity.getContentResolver();
+
+                    int count = getConversationCount(cr, accountId);
+                    if (count > 0) {
+                        mUnderBubble.setBackgroundDrawable(mBubbleDrawable);
+                        chatView.setVisibility(View.VISIBLE);
+                        chatView.setText(r.getString(R.string.conversations, count));
+
+                        providerName.setTextColor(0xff000000);
+                        loginName.setTextColor(0xff000000);
+                        chatView.setTextColor(0xff000000);
+                    } else {
+                        chatView.setVisibility(View.GONE);
+                    }
+
+                    secondRowText = cursor.getString(mActiveAccountUserNameColumn);
+                    break;
+
+                default:
+                    secondRowText = cursor.getString(mActiveAccountUserNameColumn);
+                    break;
+            }
+
+            loginName.setText(secondRowText);
+
+        } else {
+            // No active account, show add account
+            mLoginName.setVisibility(View.GONE);
+            mChatView.setVisibility(View.GONE);
+            mProviderName.setText(providerDisplayName);
+        }
+    }
+
+    private int getConversationCount(ContentResolver cr, long accountId) {
+        // TODO: this is code used to get Google Talk's chat count. Not sure if this will work
+        // for IMPS chat count.
+        StringBuilder where = new StringBuilder();
+        where.append(Im.Chats.CONTACT_ID);
+        where.append(" in (select _id from contacts where ");
+        where.append(Im.Contacts.ACCOUNT);
+        where.append("=");
+        where.append(accountId);
+        where.append(")");
+
+        Cursor cursor = cr.query(Im.Chats.CONTENT_URI, null, where.toString(), null, null);
+
+        try {
+            return cursor.getCount();
+        } finally {
+            cursor.close();
+        }
+    }
+
+    private int getPresenceIconId(Cursor cursor) {
+        int presenceStatus = cursor.getInt(mAccountPresenceStatusColumn);
+
+        if (LOCAL_DEBUG) log("getPresenceIconId: presenceStatus=" + presenceStatus);
+
+        switch (presenceStatus) {
+            case Im.Presence.AVAILABLE:
+                return BrandingResourceIDs.DRAWABLE_PRESENCE_ONLINE;
+
+            case Im.Presence.IDLE:
+            case Im.Presence.AWAY:
+                return BrandingResourceIDs.DRAWABLE_PRESENCE_AWAY;
+
+            case Im.Presence.DO_NOT_DISTURB:
+                return BrandingResourceIDs.DRAWABLE_PRESENCE_BUSY;
+
+            case Im.Presence.INVISIBLE:
+                return BrandingResourceIDs.DRAWABLE_PRESENCE_INVISIBLE;
+
+            default:
+                return BrandingResourceIDs.DRAWABLE_PRESENCE_OFFLINE;
+        }
+    }
+
+    private void log(String msg) {
+        Log.d(TAG, msg);
+    }
+}
index 5ba170b..a5b0a46 100644 (file)
@@ -20,6 +20,8 @@ package com.android.im.engine;
  * An abstract interface to access system SMS service.
  */
 public interface SmsService {
+    public static final String ANY_ADDRESS = "*";
+
     /**
      * The listener which will be notified when an incoming SMS is received.
      *
index f147d00..48228c8 100644 (file)
@@ -41,10 +41,18 @@ abstract class CirChannel {
      */
     public abstract void connect() throws ImException;
 
+    /**
+     * Re-establish the connection and drop the old one.
+     */
     public void reconnect(){
     }
 
     /**
+     * Tells if the CIR has been shutdown or not.
+     */
+    public abstract boolean isShutdown();
+
+    /**
      * Shutdown the CIR channel, stops to listen to CIR requests from the server.
      *
      */
index 5ce1f5a..c2c758d 100644 (file)
 package com.android.im.imps;
 
 import com.android.im.engine.ImException;
-import com.android.im.plugin.IPasswordDigest;
-
-import android.os.RemoteException;
+import com.android.im.plugin.PasswordDigest;
 
 import dalvik.system.PathClassLoader;
 
 public class CustomPasswordDigest implements PasswordDigest {
 
-    private IPasswordDigest mPasswordDigest;
+    private PasswordDigest mPasswordDigest;
     public CustomPasswordDigest(String pluginPath, String implClass) throws ImException {
         PathClassLoader classLoader = new PathClassLoader(pluginPath,
                 getClass().getClassLoader());
         try {
-            Class cls = classLoader.loadClass(implClass);
-            mPasswordDigest = (IPasswordDigest)cls.newInstance();
+            Class<?> cls = classLoader.loadClass(implClass);
+            mPasswordDigest = (PasswordDigest)cls.newInstance();
         } catch (ClassNotFoundException e) {
             throw new ImException(e);
         } catch (IllegalAccessException e) {
@@ -41,19 +39,11 @@ public class CustomPasswordDigest implements PasswordDigest {
         }
     }
     public String digest(String schema, String nonce, String password) throws ImException {
-        try {
-            return mPasswordDigest.digest(schema, nonce, password);
-        } catch (RemoteException e) {
-            throw new ImException(e);
-        }
+        return mPasswordDigest.digest(schema, nonce, password);
     }
 
     public String[] getSupportedDigestSchema() {
-        try {
-            return mPasswordDigest.getSupportedDigestSchema();
-        } catch (RemoteException e) {
-            return new String[0];
-        }
+        return mPasswordDigest.getSupportedDigestSchema();
     }
 
 }
index 9f7270e..e9f0176 100644 (file)
  */
 package com.android.im.imps;
 
+import java.util.Map;
+
+import android.os.RemoteException;
+
 import com.android.im.engine.ImException;
-import com.android.im.plugin.IPresenceMapping;
 import com.android.im.plugin.ImPluginConstants;
+import com.android.im.plugin.PresenceMapping;
 
 import dalvik.system.PathClassLoader;
 
-import android.os.RemoteException;
-
-import java.util.Map;
-
 public class CustomPresenceMapping implements PresenceMapping {
-    private IPresenceMapping mPresenceMapping;
+    private PresenceMapping mPresenceMapping;
 
     public CustomPresenceMapping(String pluginPath, String implClass) throws ImException {
         PathClassLoader classLoader = new PathClassLoader(pluginPath,
                 getClass().getClassLoader());
         try {
-            Class cls = classLoader.loadClass(implClass);
-            mPresenceMapping = (IPresenceMapping)cls.newInstance();
+            Class<?> cls = classLoader.loadClass(implClass);
+            mPresenceMapping = (PresenceMapping)cls.newInstance();
         } catch (ClassNotFoundException e) {
             throw new ImException(e);
         } catch (IllegalAccessException e) {
@@ -45,52 +45,28 @@ public class CustomPresenceMapping implements PresenceMapping {
     }
 
     public Map<String, Object> getExtra(int status) {
-        try {
-            return mPresenceMapping.getExtra(status);
-        } catch (RemoteException e) {
-            return null;
-        }
+        return mPresenceMapping.getExtra(status);
     }
 
     public boolean getOnlineStatus(int status) {
-        try {
-            return mPresenceMapping.getOnlineStatus(status);
-        } catch (RemoteException e) {
-            return false;
-        }
+        return mPresenceMapping.getOnlineStatus(status);
     }
 
     public int getPresenceStatus(boolean onlineStatus, String userAvailability,
             Map<String, Object> allValues) {
-        try {
-            return mPresenceMapping.getPresenceStatus(onlineStatus, userAvailability, allValues);
-        } catch (RemoteException e) {
-            return ImPluginConstants.PRESENCE_OFFLINE;
-        }
+        return mPresenceMapping.getPresenceStatus(onlineStatus, userAvailability, allValues);
     }
 
     public int[] getSupportedPresenceStatus() {
-        try {
-            return mPresenceMapping.getSupportedPresenceStatus();
-        } catch (RemoteException e) {
-            return new int[0];
-        }
+        return mPresenceMapping.getSupportedPresenceStatus();
     }
 
     public String getUserAvaibility(int status) {
-        try {
-            return mPresenceMapping.getUserAvaibility(status);
-        } catch (RemoteException e) {
-            return ImPluginConstants.PA_NOT_AVAILABLE;
-        }
+        return mPresenceMapping.getUserAvaibility(status);
     }
 
     public boolean requireAllPresenceValues() {
-        try {
-            return mPresenceMapping.requireAllPresenceValues();
-        } catch (RemoteException e) {
-            return false;
-        }
+        return mPresenceMapping.requireAllPresenceValues();
     }
 
 }
index fa5f954..bf4e4fa 100644 (file)
@@ -17,6 +17,7 @@
 package com.android.im.imps;
 
 import com.android.im.plugin.ImPluginConstants;
+import com.android.im.plugin.PresenceMapping;
 
 import java.util.Map;
 
index 1cca355..77d6bf5 100644 (file)
@@ -45,7 +45,7 @@ class HttpCirChannel extends CirChannel implements Runnable {
     }
 
     @Override
-    public void connect() {
+    public synchronized void connect() {
         ImpsSession session = mConnection.getSession();
         try {
             if (session.getCirHttpAddress() != null) {
@@ -56,13 +56,18 @@ class HttpCirChannel extends CirChannel implements Runnable {
         }
         mServerPollMin = session.getServerPollMin() * 1000;
 
+        mStopped = false;
         mPollingTask = new Thread(this, "HTTPCIRChannel");
         mPollingTask.setDaemon(true);
         mPollingTask.start();
     }
 
+    public synchronized boolean isShutdown() {
+        return mStopped;
+    }
+
     @Override
-    public void shutdown() {
+    public synchronized void shutdown() {
         mStopped = true;
     }
 
index 0986dbc..0d49a60 100644 (file)
@@ -23,6 +23,8 @@ import com.android.im.engine.ConnectionConfig;
 import com.android.im.engine.ImException;
 import com.android.im.imps.ImpsConstants.ImpsVersion;
 import com.android.im.plugin.ImpsConfigNames;
+import com.android.im.plugin.PasswordDigest;
+import com.android.im.plugin.PresenceMapping;
 
 /**
  * The configuration for IMPS connection.
index 480671d..31ddce2 100644 (file)
@@ -32,6 +32,7 @@ import com.android.im.engine.ImException;
 import com.android.im.engine.Presence;
 import com.android.im.engine.SubscriptionRequestListener;
 import com.android.im.imps.ImpsConstants.ImpsVersion;
+import com.android.im.plugin.PresenceMapping;
 
 /**
  * An implementation of ContactListManager of Wireless Village IMPS protocol.
index ec1403f..e9b0b5f 100644 (file)
@@ -18,6 +18,8 @@
 package com.android.im.imps;
 
 import com.android.im.engine.Presence;
+import com.android.im.plugin.PresenceMapping;
+
 import org.apache.commons.codec.binary.Base64;
 
 import android.os.Base64Utils;
@@ -151,7 +153,7 @@ public class ImpsPresenceUtils {
             if (value instanceof String) {
                 elem.setContents((String)value);
             } else if (value instanceof Map) {
-                mapToPrimitives((Map)value, elem.getChildren());
+                mapToPrimitives((Map<String, Object>)value, elem.getChildren());
             }
             elems.add(elem);
         }
diff --git a/src/com/android/im/imps/PasswordDigest.java b/src/com/android/im/imps/PasswordDigest.java
deleted file mode 100644 (file)
index d911fc5..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2008 Esmertec AG.
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.im.imps;
-
-import com.android.im.engine.ImException;
-
-public interface PasswordDigest {
-    /**
-     * Gets an array of supported digest schema.
-     *
-     * @return an array of digest schema
-     */
-    String[] getSupportedDigestSchema();
-
-    /**
-     * Generates digest bytes.
-     *
-     */
-    String digest(String schema, String nonce, String password) throws ImException;
-}
diff --git a/src/com/android/im/imps/PresenceMapping.java b/src/com/android/im/imps/PresenceMapping.java
deleted file mode 100644 (file)
index 04602a9..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2008 Esmertec AG.
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.im.imps;
-
-import java.util.Map;
-
-public interface PresenceMapping {
-    /**
-     * Tells if the mapping needs all presence values sent in protocol. If this
-     * method returns true, the framework will pass all the presence values
-     * received from the server when map to the predefined status.
-     *
-     * @return true if needs; false otherwise.
-     */
-    boolean requireAllPresenceValues();
-
-    /**
-     * Map the presence values sent in protocol to the predefined presence
-     * status.
-     *
-     * @param onlineStatus The value of presence &lt;OnlineStatus&gt; received
-     *            from the server.
-     * @param userAvailability The value of presence &lt;UserAvailibility&gt;
-     *            received from the server.
-     * @param allValues The whole presence values received from the server.
-     * @return a predefined status.
-     * @see #requireAllPresenceValues()
-     */
-    int getPresenceStatus(boolean onlineStatus, String userAvailability,
-             Map<String, Object> allValues);
-
-    /**
-     * Gets the value of &lt;OnlineStatus&gt; will be sent to the server when
-     * update presence to the predefined status.
-     *
-     * @param status the predefined status.
-     * @return The value of &lt;OnlineStatus&gt; will be sent to the server
-     */
-    boolean getOnlineStatus(int status);
-
-    /**
-     * Gets the value of &lt;UserAvaibility&gt; will be sent to the server when
-     * update presence to the predefined status.
-     *
-     * @param status the predefined status.
-     * @return The value of &lt;UserAvaibility&gt; will be sent to the server
-     */
-    String getUserAvaibility(int status);
-
-    /**
-     * Gets the extra presence values other than &lt;OnlineStatus&gt; and
-     * &lt;UserAvaibility&gt; will be sent to the server when update presence to
-     * the predefined status.
-     *
-     * @param status the predefined status.
-     * @return The extra values that will be sent to the server.
-     */
-    Map<String, Object> getExtra(int status);
-
-    /**
-     * Gets an array of the supported presence status. The client can only update
-     * presence to the values in the array.
-     *
-     * @return an array of the supported presence status.
-     */
-    int[] getSupportedPresenceStatus();
-}
index e7d917c..b3601db 100644 (file)
@@ -86,7 +86,9 @@ public class PresencePollingManager implements Runnable {
                         // poll. Fetch the presence of all contacts in list.
                         pollingAddress = getContactLists();
                     }
-                    mManager.fetchPresence(pollingAddress);
+                    if (pollingAddress != null) {
+                        mManager.fetchPresence(pollingAddress);
+                    }
                 }
 
                 try {
index 24ece3b..12f9f1d 100644 (file)
@@ -16,6 +16,8 @@
  */
 package com.android.im.imps;
 
+import android.util.Log;
+
 import com.android.im.engine.ImErrorInfo;
 import com.android.im.engine.ImException;
 import com.android.im.engine.SmsService;
@@ -41,13 +43,17 @@ public class SmsCirChannel extends CirChannel
 
     @Override
     public void connect() throws ImException {
-        if (mAddr == null || mAddr.length() == 0) {
-            throw new ImException(ImpsErrorInfo.UNKNOWN_SERVER,
-                    "Invalid sms addr");
-        }
         mSmsService = SystemService.getDefault().getSmsService();
-        mSmsService.addSmsListener(mAddr, mPort, this);
-        sendHelo();
+        if (mAddr != null) {
+            mSmsService.addSmsListener(mAddr, mPort, this);
+            sendHelo();
+        } else {
+            mSmsService.addSmsListener(SmsService.ANY_ADDRESS, mPort, this);
+        }
+    }
+
+    public boolean isShutdown() {
+        return false;
     }
 
     @Override
@@ -59,23 +65,23 @@ public class SmsCirChannel extends CirChannel
         // It's safe to assume that each character is encoded into 7-bit since
         // all characters in CIR are in gsm 7-bit alphabet.
         int lengthSeptets = data.length * 8 / 7;
-        int numPaddingBits = data.length * 8 % 7;
         String s = GsmAlphabet.gsm7BitPackedToString(data, 0,
-                lengthSeptets, numPaddingBits);
+                lengthSeptets, 0);
         // CIR format: WVCI <version> <session cookie>
         if (!s.startsWith("WVCI")) {
             // not a valid CIR, ignore.
+            Log.w("SmsCir", "Received a non-CIR SMS, ignore!");
             return;
         }
+
+        String sessionCookie = mConnection.getSession().getCookie();
         String[] fields = s.split(" ");
-        if (fields.length != 3) {
+        if (fields.length != 3 || !sessionCookie.equalsIgnoreCase(fields[2])) {
             // Not a valid CIR, ignore
-            return;
-        }
-        String sessionCookie = mConnection.getSession().getCookie();
-        if (sessionCookie.equalsIgnoreCase(fields[2])) {
-            mConnection.sendPollingRequest();
+            Log.w("SmsCir", "The CIR format is not correct or session cookie" +
+                    " does not match");
         }
+        mConnection.sendPollingRequest();
     }
 
     public void onFailure(int errorCode) {
index dd7bbaf..e88f377 100644 (file)
@@ -18,6 +18,7 @@
 package com.android.im.imps;
 
 import com.android.im.engine.ImException;
+import com.android.im.plugin.PasswordDigest;
 
 import org.apache.commons.codec.binary.Base64;
 
index 6679a0a..45dfdcd 100644 (file)
@@ -62,6 +62,7 @@ class TcpCirChannel extends CirChannel implements Runnable, HeartbeatService.Cal
     @Override
     public synchronized void connect() throws ImException {
         try {
+            mDone = false;
             connectServer();
             mCirThread = new Thread(this, "TcpCirChannel");
             mCirThread.setDaemon(true);
@@ -86,8 +87,8 @@ class TcpCirChannel extends CirChannel implements Runnable, HeartbeatService.Cal
             ImpsLog.log(mUser + " Shutting down CIR channel");
         }
         mDone = true;
-        synchronized (mReconnectLock) {
-            if (mReconnecting) {
+        if (mReconnecting) {
+            synchronized (mReconnectLock) {
                 mReconnecting = false;
                 mReconnectLock.notify();
             }
@@ -106,6 +107,10 @@ class TcpCirChannel extends CirChannel implements Runnable, HeartbeatService.Cal
         }
     }
 
+    public boolean isShutdown() {
+        return mDone;
+    }
+
     public void run() {
         while (!mDone) {
             try {
index fe7aa29..659451f 100644 (file)
@@ -17,7 +17,8 @@
 
 package com.android.im.service;
 
-import com.android.im.engine.HeartbeatService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
@@ -31,6 +32,8 @@ import android.os.PowerManager;
 import android.os.SystemClock;
 import android.util.SparseArray;
 
+import com.android.im.engine.HeartbeatService;
+
 public class AndroidHeartBeatService extends BroadcastReceiver
         implements HeartbeatService {
 
@@ -43,16 +46,18 @@ public class AndroidHeartBeatService extends BroadcastReceiver
     private static final String HEARTBEAT_CONTENT_TYPE
             = "vnd.android.im/heartbeat";
 
-    private Context mContext;
-    private AlarmManager mAlarmManager;
-    private PowerManager.WakeLock mWakeLock;
+    private static final ExecutorService sExecutor = Executors.newSingleThreadExecutor();
+
+    private final Context mContext;
+    private final AlarmManager mAlarmManager;
+    /*package*/ PowerManager.WakeLock mWakeLock;
 
     static class Alarm {
         public PendingIntent mAlaramSender;
         public Callback mCallback;
     }
 
-    private SparseArray<Alarm> mAlarms;
+    private final SparseArray<Alarm> mAlarms;
 
     public AndroidHeartBeatService(Context context) {
         mContext = context;
@@ -72,7 +77,8 @@ public class AndroidHeartBeatService extends BroadcastReceiver
             int id = nextId();
             alarm.mCallback = callback;
             Uri data = ContentUris.withAppendedId(HEARTBEAT_CONTENT_URI, id);
-            Intent i = new Intent().setDataAndType(data, HEARTBEAT_CONTENT_TYPE);
+            Intent i = new Intent(HEARTBEAT_INTENT_ACTION)
+                            .setDataAndType(data, HEARTBEAT_CONTENT_TYPE);
             alarm.mAlaramSender = PendingIntent.getBroadcast(mContext, 0, i, 0);
             if (mAlarms.size() == 0) {
                 mContext.registerReceiver(this, IntentFilter.create(
@@ -99,22 +105,34 @@ public class AndroidHeartBeatService extends BroadcastReceiver
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        mWakeLock.acquire();
-        try {
-            int id = (int)ContentUris.parseId(intent.getData());
-            Alarm alarm = mAlarms.get(id);
-            if (alarm == null) {
-                return;
-            }
-            Callback callback = alarm.mCallback;
-            long nextSchedule = callback.sendHeartbeat();
-            if (nextSchedule <= 0) {
-                cancelAlarm(alarm);
-            } else {
-                setAlarm(alarm, nextSchedule);
+        int id = (int)ContentUris.parseId(intent.getData());
+        Alarm alarm = mAlarms.get(id);
+        if (alarm == null) {
+            return;
+        }
+        sExecutor.execute(new Worker(alarm));
+    }
+
+    private class Worker implements Runnable {
+        private final Alarm mAlarm;
+
+        public Worker(Alarm alarm) {
+            mAlarm = alarm;
+        }
+
+        public void run() {
+            mWakeLock.acquire();
+            try {
+                Callback callback = mAlarm.mCallback;
+                long nextSchedule = callback.sendHeartbeat();
+                if (nextSchedule <= 0) {
+                    cancelAlarm(mAlarm);
+                } else {
+                    setAlarm(mAlarm, nextSchedule);
+                }
+            } finally {
+                mWakeLock.release();
             }
-        } finally {
-            mWakeLock.release();
         }
     }
 
@@ -128,13 +146,13 @@ public class AndroidHeartBeatService extends BroadcastReceiver
         return null;
     }
 
-    private void setAlarm(Alarm alarm, long offset) {
+    /*package*/ synchronized void setAlarm(Alarm alarm, long offset) {
         long triggerAtTime = SystemClock.elapsedRealtime() + offset;
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime,
                 alarm.mAlaramSender);
     }
 
-    private void cancelAlarm(Alarm alarm) {
+    /*package*/  synchronized void cancelAlarm(Alarm alarm) {
         mAlarmManager.cancel(alarm.mAlaramSender);
         int index = mAlarms.indexOfValue(alarm);
         if (index >= 0) {
index ddcb24e..9a32e1c 100644 (file)
@@ -49,6 +49,7 @@ public class AndroidSmsService implements SmsService {
     private Context mContext;
     private SmsReceiver mSmsReceiver;
     private IntentFilter mIntentFilter;
+    private boolean mStarted;
     /*package*/HashMap<Integer, ListenerList> mListeners;
     /*package*/HashMap<Long, SmsSendFailureCallback> mFailureCallbacks;
 
@@ -110,11 +111,17 @@ public class AndroidSmsService implements SmsService {
         if (l == null) {
             l = new ListenerList(port);
             mListeners.put(port, l);
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                log("Register SMS receiver on port " + port);
+            }
 
             // We didn't listen on the port yet, register the receiver with the
             // additional port.
             mIntentFilter.addDataAuthority("*", String.valueOf(port));
             mContext.registerReceiver(mSmsReceiver, mIntentFilter);
+            synchronized (this) {
+                mStarted = true;
+            }
         }
         l.addListener(from, listener);
     }
@@ -130,8 +137,11 @@ public class AndroidSmsService implements SmsService {
         }
     }
 
-    public void stop() {
-        mContext.unregisterReceiver(mSmsReceiver);
+    public synchronized void stop() {
+        if (mStarted) {
+            mContext.unregisterReceiver(mSmsReceiver);
+            mStarted = false;
+        }
     }
 
     private static long sNextMsgId = 0;
@@ -166,6 +176,11 @@ public class AndroidSmsService implements SmsService {
             } else if (DATA_SMS_RECEIVED_ACTION.equals(intent.getAction())){
                 Uri uri = intent.getData();
                 int port = uri.getPort();
+
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    log("Received sms on port:" + port);
+                }
+
                 ListenerList listeners = mListeners.get(port);
                 if (listeners == null) {
                     if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -219,7 +234,10 @@ public class AndroidSmsService implements SmsService {
         public void notifySms(String addr, byte[] data) {
             int N = mListenerList.size();
             for (int i = 0; i < N; i++) {
-                if (PhoneNumberUtils.compare(addr, mAddrList.get(i))) {
+                String listenAddr = mAddrList.get(i);
+                if (ANY_ADDRESS.equals(listenAddr)
+                        || addr.equals(listenAddr)
+                        || PhoneNumberUtils.compare(addr, listenAddr)) {
                     mListenerList.get(i).onIncomingSms(data);
                 }
             }
index cb350bd..ea1cb85 100644 (file)
@@ -28,14 +28,9 @@ import java.util.Vector;
 import android.app.Service;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
 import android.database.Cursor;
 import android.net.ConnectivityManager;
 import android.net.NetworkConnectivityListener;
@@ -55,20 +50,18 @@ import android.text.TextUtils;
 import android.util.Log;
 import android.widget.Toast;
 
-import com.android.im.app.DatabaseUtils;
 import com.android.im.IConnectionCreationListener;
 import com.android.im.IImConnection;
 import com.android.im.IRemoteImService;
+import com.android.im.app.ImPluginHelper;
 import com.android.im.engine.ConnectionFactory;
 import com.android.im.engine.ImConnection;
 import com.android.im.engine.ImException;
 import com.android.im.imps.ImpsConnectionConfig;
-import com.android.im.plugin.IImPlugin;
 import com.android.im.plugin.ImConfigNames;
-import com.android.im.plugin.ImPluginConstants;
 import com.android.im.plugin.ImPluginInfo;
 import com.android.im.plugin.ImpsConfigNames;
-import dalvik.system.PathClassLoader;
+
 
 public class RemoteImService extends Service {
 
@@ -98,15 +91,14 @@ public class RemoteImService extends Service {
 
     private SettingsMonitor mSettingsMonitor;
 
+    private ImPluginHelper mPluginHelper;
     Vector<ImConnectionAdapter> mConnections;
     final RemoteCallbackList<IConnectionCreationListener> mRemoteListeners
             = new RemoteCallbackList<IConnectionCreationListener>();
 
-    private HashMap<Long, ImPluginInfo> mPlugins;
 
     public RemoteImService() {
         mConnections = new Vector<ImConnectionAdapter>();
-        mPlugins = new HashMap<Long, ImPluginInfo>();
     }
 
     @Override
@@ -128,89 +120,11 @@ public class RemoteImService extends Service {
             = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
         setBackgroundData(manager.getBackgroundDataSetting());
 
-        findAvaiablePlugins();
+        mPluginHelper = ImPluginHelper.getInstance(this);
+        mPluginHelper.loadAvaiablePlugins();
         AndroidSystemService.getInstance().initialize(this);
     }
 
-    private void findAvaiablePlugins() {
-        PackageManager pm = getPackageManager();
-        List<ResolveInfo> plugins = pm.queryIntentServices(
-                new Intent(ImPluginConstants.PLUGIN_ACTION_NAME), PackageManager.GET_META_DATA);
-        for (ResolveInfo info : plugins) {
-            Log.d(TAG, "Found plugin " + info);
-
-            ServiceInfo serviceInfo = info.serviceInfo;
-            if (serviceInfo == null) {
-                Log.e(TAG, "Ignore bad IM plugin: " + info);
-                continue;
-            }
-            String providerName = null;
-            String providerFullName = null;
-            String signUpUrl = null;
-            Bundle metaData = serviceInfo.metaData;
-            if (metaData != null) {
-                providerName = metaData.getString(ImPluginConstants.METADATA_PROVIDER_NAME);
-                providerFullName = metaData.getString(ImPluginConstants.METADATA_PROVIDER_FULL_NAME);
-                signUpUrl = metaData.getString(ImPluginConstants.METADATA_SIGN_UP_URL);
-            }
-            if (TextUtils.isEmpty(providerName) || TextUtils.isEmpty(providerFullName)) {
-                Log.e(TAG, "Ignore bad IM plugin: " + info + ". Lack of required meta data");
-                continue;
-            }
-
-            ImPluginInfo pluginInfo = new ImPluginInfo(providerName, serviceInfo.packageName,
-                    serviceInfo.name, serviceInfo.applicationInfo.sourceDir);
-
-            Map<String, String> config = loadProviderConfigFromPlugin(pluginInfo);
-            if (config == null) {
-                Log.e(TAG, "Ignore bad IM plugin");
-                break;
-            }
-
-            config.put(ImConfigNames.PLUGIN_PATH, pluginInfo.mSrcPath);
-            config.put(ImConfigNames.PLUGIN_CLASS, pluginInfo.mClassName);
-            long providerId = DatabaseUtils.updateProviderDb(getContentResolver(),
-                    providerName, providerFullName, signUpUrl, config);
-            mPlugins.put(providerId, pluginInfo);
-        }
-    }
-
-    private Map<String, String> loadProviderConfigFromPlugin(ImPluginInfo pluginInfo) {
-        // XXX Load the plug-in implementation directly from the apk rather than
-        // binding to the service and call through IPC Binder API. This is much
-        // more effective since we don't need to start the service in other
-        // process. We can not run the plug-in service in the same process as a
-        // local service because that the interface is defined in a shared
-        // library in order to compile the plug-in separately. In this case, the
-        // interface will be loaded by two class loader separately and a
-        // ClassCastException will be thrown if we cast the binder to the
-        // interface.
-        PathClassLoader loader = new PathClassLoader(pluginInfo.mSrcPath, getClassLoader());
-        try {
-            Class cls = loader.loadClass(pluginInfo.mClassName);
-            Method m = cls.getMethod("onBind", Intent.class);
-            IImPlugin plugin = (IImPlugin)m.invoke(cls.newInstance(), new Object[]{null});
-            return plugin.getProviderConfig();
-        } catch (ClassNotFoundException e) {
-            Log.e(TAG, "Could not find plugin class", e);
-        } catch (IllegalAccessException e) {
-            Log.e(TAG, "Could not create plugin instance", e);
-        } catch (InstantiationException e) {
-            Log.e(TAG, "Could not create plugin instance", e);
-        } catch (SecurityException e) {
-            Log.e(TAG, "Could not load config from the plugin", e);
-        } catch (NoSuchMethodException e) {
-            Log.e(TAG, "Could not load config from the plugin", e);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Could not load config from the plugin", e);
-        } catch (InvocationTargetException e) {
-            Log.e(TAG, "Could not load config from the plugin", e);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Could not load config from the plugin", e);
-        }
-        return null;
-    }
-
     @Override
     public void onStart(Intent intent, int startId) {
         super.onStart(intent, startId);
@@ -454,8 +368,8 @@ public class RemoteImService extends Service {
 
     private final IRemoteImService.Stub mBinder = new IRemoteImService.Stub() {
 
-        public List getAllPlugins() {
-            return new ArrayList(mPlugins.values());
+        public List<ImPluginInfo> getAllPlugins() {
+            return new ArrayList<ImPluginInfo>(mPluginHelper.getPluginsInfo());
         }
 
         public void addConnectionCreatedListener(IConnectionCreationListener listener) {