Merge "Import translations. DO NOT MERGE"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2ec746e..37b78c0 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -47,6 +47,7 @@
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
 
     <application
+        android:name="DialerApplication"
         android:label="@string/applicationLabel"
         android:icon="@mipmap/ic_launcher_phone"
         android:hardwareAccelerated="true"
diff --git a/src/com/android/dialer/DialerApplication.java b/src/com/android/dialer/DialerApplication.java
new file mode 100644
index 0000000..39a1ac7
--- /dev/null
+++ b/src/com/android/dialer/DialerApplication.java
@@ -0,0 +1,16 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+
+package com.android.dialer;
+
+import android.app.Application;
+
+import com.android.contacts.common.extensions.ExtensionsFactory;
+
+public class DialerApplication extends Application {
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        ExtensionsFactory.init(getApplicationContext());
+    }
+}
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index 499ff31..d8fe1ab 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -77,6 +77,7 @@
 import com.android.dialer.list.PhoneFavoriteFragment;
 import com.android.dialer.list.OnListFragmentScrolledListener;
 import com.android.dialer.list.SmartDialSearchFragment;
+import com.android.dialerbind.DatabaseHelperManager;
 import com.android.internal.telephony.ITelephony;
 
 import java.util.ArrayList;
@@ -181,12 +182,14 @@
                     // CallLog screen (search UI will be automatically exited).
                     PhoneNumberInteraction.startInteractionForPhoneCall(
                         DialtactsActivity.this, dataUri, getCallOrigin());
+                    hideDialpadAndSearchUi();
                 }
 
                 @Override
                 public void onCallNumberDirectly(String phoneNumber) {
                     Intent intent = CallUtil.getCallIntent(phoneNumber, getCallOrigin());
                     startActivity(intent);
+                    hideDialpadAndSearchUi();
                 }
 
                 @Override
@@ -285,7 +288,7 @@
             setupFilterText(intent);
         }
 
-        mDialerDatabaseHelper = DialerDatabaseHelper.getInstance(this);
+        mDialerDatabaseHelper = DatabaseHelperManager.getDatabaseHelper(this);
         SmartDialPrefix.initializeNanpSettings(this);
     }
 
@@ -430,7 +433,12 @@
         ft.commit();
     }
 
-    private void hideDialpadFragment(boolean animate) {
+    private void hideDialpadFragment(boolean animate, boolean clearDialpad) {
+        if (mDialpadFragment == null) return;
+        if (clearDialpad) {
+            mDialpadFragment.clearDialpad();
+        }
+        if (!mDialpadFragment.isVisible()) return;
         mDialpadFragment.setAdjustTranslationForAnimation(animate);
         final FragmentTransaction ft = getFragmentManager().beginTransaction();
         if (animate) {
@@ -459,12 +467,6 @@
         });
     }
 
-    private void hideDialpadFragmentIfNecessary() {
-        if (mDialpadFragment != null && mDialpadFragment.isVisible()) {
-            hideDialpadFragment(true);
-        }
-    }
-
     final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
@@ -472,6 +474,13 @@
         }
     };
 
+    private void hideDialpadAndSearchUi() {
+        if (mInSearchUi) {
+            exitSearchUi();
+        }
+        hideDialpadFragment(false, true);
+    }
+
     public void hideSearchBar() {
        hideSearchBar(true);
     }
@@ -793,9 +802,10 @@
     @Override
     public void onBackPressed() {
         if (mDialpadFragment != null && mDialpadFragment.isVisible()) {
-            hideDialpadFragment(true);
+            hideDialpadFragment(true, false);
         } else if (mInSearchUi) {
             mSearchView.setText(null);
+            mDialpadFragment.clearDialpad();
         } else if (isTaskRoot()) {
             // Instead of stopping, simply push this to the back of the stack.
             // This is only done when running at the top of the stack;
@@ -830,7 +840,7 @@
     @Override
     public void onListFragmentScrollStateChange(int scrollState) {
         if (scrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
-            hideDialpadFragmentIfNecessary();
+            hideDialpadFragment(true, false);
             hideInputMethod(getCurrentFocus());
         }
     }
diff --git a/src/com/android/dialer/SearchFragment.java b/src/com/android/dialer/SearchFragment.java
index 38b7e77..a0b8908 100644
--- a/src/com/android/dialer/SearchFragment.java
+++ b/src/com/android/dialer/SearchFragment.java
@@ -16,13 +16,11 @@
 package com.android.dialer;
 
 import android.app.Activity;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
 import android.widget.AbsListView;
 import android.widget.AbsListView.OnScrollListener;
 
-import com.android.contacts.common.list.ContactListItemView;
 import com.android.contacts.common.list.ContactEntryListAdapter;
+import com.android.contacts.common.list.ContactListItemView;
 import com.android.contacts.common.list.PhoneNumberPickerFragment;
 import com.android.dialer.list.OnListFragmentScrolledListener;
 
diff --git a/src/com/android/dialer/database/DialerDatabaseHelper.java b/src/com/android/dialer/database/DialerDatabaseHelper.java
index 3bea980..2fa561f 100644
--- a/src/com/android/dialer/database/DialerDatabaseHelper.java
+++ b/src/com/android/dialer/database/DialerDatabaseHelper.java
@@ -16,11 +16,13 @@
 
 package com.android.dialer.database;
 
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteStatement;
 import android.net.Uri;
@@ -31,6 +33,7 @@
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.Directory;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.contacts.common.util.StopWatch;
@@ -68,14 +71,15 @@
      *   0-98   KeyLimePie
      * </pre>
      */
-    private static final int DATABASE_VERSION = 2;
-    private static final String SMARTDIAL_DATABASE_NAME = "dialer.db";
+    public static final int DATABASE_VERSION = 3;
+    public static final String DATABASE_NAME = "dialer.db";
 
     /**
      * Saves the last update time of smart dial databases to shared preferences.
      */
-    private static final String DATABASE_LAST_CREATED_SHARED_PREF = "com.android.dialer_smartdial";
+    private static final String DATABASE_LAST_CREATED_SHARED_PREF = "com.android.dialer";
     private static final String LAST_UPDATED_MILLIS = "last_updated_millis";
+    private static final String DATABASE_VERSION_PROPERTY = "database_version";
 
     private static final int MAX_ENTRIES = 20;
 
@@ -84,6 +88,8 @@
         static final String SMARTDIAL_TABLE = "smartdial_table";
         /** Saves all possible prefixes to refer to a contacts.*/
         static final String PREFIX_TABLE = "prefix_table";
+        /** Database properties for internal use */
+        static final String PROPERTIES = "properties";
     }
 
     public interface SmartDialDbColumns {
@@ -108,6 +114,11 @@
         static final String CONTACT_ID = "contact_id";
     }
 
+    public interface PropertiesColumns {
+        String PROPERTY_KEY = "property_key";
+        String PROPERTY_VALUE = "property_value";
+    }
+
     /** Query options for querying the contact database.*/
     public static interface PhoneQuery {
        static final Uri URI = Phone.CONTENT_URI.buildUpon().
@@ -297,7 +308,7 @@
             // and we don't want to leak the activity if the activity is not running but the
             // dialer database helper is still doing work.
             sSingleton = new DialerDatabaseHelper(context.getApplicationContext(),
-                    SMARTDIAL_DATABASE_NAME);
+                    DATABASE_NAME);
         }
         return sSingleton;
     }
@@ -311,7 +322,11 @@
     }
 
     protected DialerDatabaseHelper(Context context, String databaseName) {
-        super(context, databaseName, null, DATABASE_VERSION);
+        this(context, databaseName, DATABASE_VERSION);
+    }
+
+    protected DialerDatabaseHelper(Context context, String databaseName, int dbVersion) {
+        super(context, databaseName, null, dbVersion);
         mContext = Preconditions.checkNotNull(context, "Context must not be null");
     }
 
@@ -344,28 +359,115 @@
                 PrefixColumns.PREFIX + " TEXT COLLATE NOCASE, " +
                 PrefixColumns.CONTACT_ID + " INTEGER" +
                 ");");
+
+        db.execSQL("CREATE TABLE " + Tables.PROPERTIES + " (" +
+                PropertiesColumns.PROPERTY_KEY + " TEXT PRIMARY KEY, " +
+                PropertiesColumns.PROPERTY_VALUE + " TEXT " +
+                ");");
+
+        setProperty(db, DATABASE_VERSION_PROPERTY, String.valueOf(DATABASE_VERSION));
+        resetSmartDialLastUpdatedTime();
     }
 
     @Override
-    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-        Log.w(TAG, oldVersion + " to " + newVersion + ", rebuilding table");
+    public void onUpgrade(SQLiteDatabase db, int oldNumber, int newNumber) {
+        // Disregard the old version and new versions provided by SQLiteOpenHelper, we will read
+        // our own from the database.
 
+        int oldVersion;
+
+        oldVersion = getPropertyAsInt(db, DATABASE_VERSION_PROPERTY, 0);
+
+        if (oldVersion == 0) {
+            Log.e(TAG, "Malformed database version..recreating database");
+        }
+
+        if (oldVersion < 2) {
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.PREFIX_TABLE);
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.SMARTDIAL_TABLE);
+            onCreate(db);
+            return;
+        }
+
+        if (oldVersion < 3) {
+            db.execSQL("CREATE TABLE " + Tables.PROPERTIES + " (" +
+                    PropertiesColumns.PROPERTY_KEY + " TEXT PRIMARY KEY, " +
+                    PropertiesColumns.PROPERTY_VALUE + " TEXT " +
+                    ");");
+            oldVersion = 3;
+        }
+
+        if (oldVersion != DATABASE_VERSION) {
+            throw new IllegalStateException(
+                    "error upgrading the database to version " + DATABASE_VERSION);
+        }
+
+        setProperty(db, DATABASE_VERSION_PROPERTY, String.valueOf(DATABASE_VERSION));
+    }
+
+    /**
+     * Stores a key-value pair in the {@link Tables#PROPERTIES} table.
+     */
+    public void setProperty(String key, String value) {
+        setProperty(getWritableDatabase(), key, value);
+    }
+
+    public void setProperty(SQLiteDatabase db, String key, String value) {
+        final ContentValues values = new ContentValues();
+        values.put(PropertiesColumns.PROPERTY_KEY, key);
+        values.put(PropertiesColumns.PROPERTY_VALUE, value);
+        db.replace(Tables.PROPERTIES, null, values);
+    }
+
+    /**
+     * Returns the value from the {@link Tables#PROPERTIES} table.
+     */
+    public String getProperty(String key, String defaultValue) {
+        return getProperty(getReadableDatabase(), key, defaultValue);
+    }
+
+    public String getProperty(SQLiteDatabase db, String key, String defaultValue) {
+        try {
+            final Cursor cursor = db.query(Tables.PROPERTIES,
+                    new String[] {PropertiesColumns.PROPERTY_VALUE},
+                            PropertiesColumns.PROPERTY_KEY + "=?",
+                    new String[] {key}, null, null, null);
+            String value = null;
+            try {
+                if (cursor.moveToFirst()) {
+                    value = cursor.getString(0);
+                }
+            } finally {
+                cursor.close();
+            }
+            return value != null ? value : defaultValue;
+        } catch (SQLiteException e) {
+            return defaultValue;
+        }
+    }
+
+    public int getPropertyAsInt(SQLiteDatabase db, String key, int defaultValue) {
+        final String stored = getProperty(db, DATABASE_VERSION_PROPERTY, "");
+        try {
+            return Integer.parseInt(stored);
+        } catch (NumberFormatException e) {
+            return defaultValue;
+        }
+    }
+
+    private void resetSmartDialLastUpdatedTime() {
         final SharedPreferences databaseLastUpdateSharedPref = mContext.getSharedPreferences(
                 DATABASE_LAST_CREATED_SHARED_PREF, Context.MODE_PRIVATE);
         final SharedPreferences.Editor editor = databaseLastUpdateSharedPref.edit();
         editor.putLong(LAST_UPDATED_MILLIS, 0);
         editor.commit();
-
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.PREFIX_TABLE);
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.SMARTDIAL_TABLE);
-        onCreate(db);
     }
 
     /**
      * Starts the database upgrade process in the background.
      */
     public void startSmartDialUpdateThread() {
-       new SmartDialUpdateAsyncTask().execute();
+        new SmartDialUpdateAsyncTask().execute();
     }
 
     private class SmartDialUpdateAsyncTask extends AsyncTask {
diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java
index 82f5377..79e8307 100644
--- a/src/com/android/dialer/dialpad/DialpadFragment.java
+++ b/src/com/android/dialer/dialpad/DialpadFragment.java
@@ -745,7 +745,7 @@
 
         if (mClearDigitsOnStop) {
             mClearDigitsOnStop = false;
-            mDigits.getText().clear();
+            clearDialpad();
         }
     }
 
@@ -1157,6 +1157,10 @@
         }
     }
 
+    public void clearDialpad() {
+        mDigits.getText().clear();
+    }
+
     private String getCallOrigin() {
         return (getActivity() instanceof DialtactsActivity) ?
                 ((DialtactsActivity) getActivity()).getCallOrigin() : null;
diff --git a/src/com/android/dialer/dialpad/SmartDialCursorLoader.java b/src/com/android/dialer/dialpad/SmartDialCursorLoader.java
index ee4a7a1..f558e37 100644
--- a/src/com/android/dialer/dialpad/SmartDialCursorLoader.java
+++ b/src/com/android/dialer/dialpad/SmartDialCursorLoader.java
@@ -27,6 +27,7 @@
 import com.android.contacts.common.list.PhoneNumberListAdapter.PhoneQuery;
 import com.android.dialer.database.DialerDatabaseHelper;
 import com.android.dialer.database.DialerDatabaseHelper.ContactNumber;
+import com.android.dialerbind.DatabaseHelperManager;
 
 import java.util.ArrayList;
 
@@ -76,7 +77,8 @@
         }
 
         /** Loads results from the database helper. */
-        DialerDatabaseHelper dialerDatabaseHelper = DialerDatabaseHelper.getInstance(mContext);
+        final DialerDatabaseHelper dialerDatabaseHelper = DatabaseHelperManager.getDatabaseHelper(
+                mContext);
         final ArrayList<ContactNumber> allMatches = dialerDatabaseHelper.getLooseMatches(mQuery,
                 mNameMatcher);
 
diff --git a/src/com/android/dialer/list/SwipeHelper.java b/src/com/android/dialer/list/SwipeHelper.java
index f493c9d..1521714 100644
--- a/src/com/android/dialer/list/SwipeHelper.java
+++ b/src/com/android/dialer/list/SwipeHelper.java
@@ -270,7 +270,7 @@
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                mCallback.onChildDismissed(mCurrView);
+                mCallback.onChildDismissed(view);
                 animView.setLayerType(View.LAYER_TYPE_NONE, null);
             }
         });
diff --git a/src/com/android/dialerbind/DatabaseHelperManager.java b/src/com/android/dialerbind/DatabaseHelperManager.java
new file mode 100644
index 0000000..c929932
--- /dev/null
+++ b/src/com/android/dialerbind/DatabaseHelperManager.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2013 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.dialerbind;
+
+import android.content.Context;
+
+import com.android.dialer.database.DialerDatabaseHelper;
+
+
+public class DatabaseHelperManager {
+    public static DialerDatabaseHelper getDatabaseHelper(Context context) {
+        return DialerDatabaseHelper.getInstance(context);
+    }
+}