Merge "Fix crash when rotating in multi-window mode." into nyc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 777faa3..05ee493 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -17,8 +17,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.dialer"
     coreApp="true"
-    android:versionCode="20501"
-    android:versionName="2.05.01">
+    android:versionCode="20502"
+    android:versionName="2.05.02">
 
     <uses-sdk
         android:minSdkVersion="23"
@@ -245,6 +245,9 @@
         <activity android:name="com.android.contacts.common.vcard.ExportVCardActivity"
                   android:theme="@style/BackgroundOnlyTheme"/>
 
+        <activity android:name="com.android.contacts.common.vcard.ShareVCardActivity"
+                  android:theme="@style/BackgroundOnlyTheme" />
+
         <service
             android:name="com.android.contacts.common.vcard.VCardService"
             android:exported="false"/>
@@ -329,5 +332,15 @@
             android:exported="false"
             android:multiprocess="false"
             />
+
+        <provider
+            android:name="android.support.v4.content.FileProvider"
+            android:authorities="@string/contacts_file_provider_authority"
+            android:grantUriPermissions="true"
+            android:exported="false">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/file_paths" />
+        </provider>
     </application>
 </manifest>
diff --git a/InCallUI/res/layout-h600dp/call_card_fragment.xml b/InCallUI/res/layout-h500dp/call_card_fragment.xml
similarity index 100%
rename from InCallUI/res/layout-h600dp/call_card_fragment.xml
rename to InCallUI/res/layout-h500dp/call_card_fragment.xml
diff --git a/InCallUI/res/layout-w600dp-land/call_card_fragment.xml b/InCallUI/res/layout-w500dp-land/call_card_fragment.xml
similarity index 100%
rename from InCallUI/res/layout-w600dp-land/call_card_fragment.xml
rename to InCallUI/res/layout-w500dp-land/call_card_fragment.xml
diff --git a/InCallUI/res/values-h600dp/dimens.xml b/InCallUI/res/values-h500dp/dimens.xml
similarity index 100%
rename from InCallUI/res/values-h600dp/dimens.xml
rename to InCallUI/res/values-h500dp/dimens.xml
diff --git a/InCallUI/res/values-w600dp-land/colors.xml b/InCallUI/res/values-w500dp-land/colors.xml
similarity index 100%
rename from InCallUI/res/values-w600dp-land/colors.xml
rename to InCallUI/res/values-w500dp-land/colors.xml
diff --git a/InCallUI/res/values-w600dp-land/dimens.xml b/InCallUI/res/values-w500dp-land/dimens.xml
similarity index 100%
rename from InCallUI/res/values-w600dp-land/dimens.xml
rename to InCallUI/res/values-w500dp-land/dimens.xml
diff --git a/InCallUI/src/com/android/incallui/CallerInfoAsyncQuery.java b/InCallUI/src/com/android/incallui/CallerInfoAsyncQuery.java
index bf5e1a3..590afaf 100644
--- a/InCallUI/src/com/android/incallui/CallerInfoAsyncQuery.java
+++ b/InCallUI/src/com/android/incallui/CallerInfoAsyncQuery.java
@@ -18,13 +18,13 @@
 
 import com.google.common.primitives.Longs;
 
+import android.Manifest;
 import android.content.AsyncQueryHandler;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -35,6 +35,7 @@
 
 import com.android.contacts.common.ContactsUtils;
 import com.android.contacts.common.compat.DirectoryCompat;
+import com.android.contacts.common.util.PermissionsUtil;
 import com.android.contacts.common.util.TelephonyManagerUtils;
 import com.android.dialer.calllog.ContactInfoHelper;
 import com.android.dialer.service.CachedNumberLookupService;
@@ -339,6 +340,12 @@
         Log.d(LOG_TAG, "##### CallerInfoAsyncQuery startContactProviderQuery()... #####");
         Log.d(LOG_TAG, "- number: " + info.phoneNumber);
         Log.d(LOG_TAG, "- cookie: " + cookie);
+        if (!PermissionsUtil.hasPermission(context, Manifest.permission.READ_CONTACTS)) {
+            Log.w(LOG_TAG, "Dialer doesn't have permission to read contacts.");
+            listener.onQueryComplete(token, cookie, info);
+            return;
+        }
+
         OnQueryCompleteListener contactsProviderQueryCompleteListener =
                 new OnQueryCompleteListener() {
                     @Override
diff --git a/res/drawable/ic_voicemail_seek_handle.xml b/res/drawable/ic_voicemail_seek_handle.xml
index a6f02be..d3fc95a 100644
--- a/res/drawable/ic_voicemail_seek_handle.xml
+++ b/res/drawable/ic_voicemail_seek_handle.xml
@@ -16,6 +16,5 @@
   -->
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
         android:src="@drawable/ic_handle"
-        android:autoMirrored="true"
         android:tint="@color/actionbar_background_color" >
 </bitmap>
\ No newline at end of file
diff --git a/res/xml/file_paths.xml b/res/xml/file_paths.xml
new file mode 100644
index 0000000..45caed2
--- /dev/null
+++ b/res/xml/file_paths.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- Offer access to files under Context.getCacheDir() -->
+    <cache-path name="my_cache" />
+</paths>
diff --git a/src/com/android/dialer/calllog/DefaultVoicemailNotifier.java b/src/com/android/dialer/calllog/DefaultVoicemailNotifier.java
index db82295..af59686 100644
--- a/src/com/android/dialer/calllog/DefaultVoicemailNotifier.java
+++ b/src/com/android/dialer/calllog/DefaultVoicemailNotifier.java
@@ -16,11 +16,6 @@
 
 package com.android.dialer.calllog;
 
-import static android.Manifest.permission.READ_CALL_LOG;
-import static android.Manifest.permission.READ_CONTACTS;
-
-import com.android.contacts.common.ContactsUtils;
-import com.android.contacts.common.compat.TelephonyManagerCompat;
 import com.google.common.collect.Maps;
 
 import android.app.Notification;
@@ -33,11 +28,15 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.support.annotation.Nullable;
+import android.support.v4.util.Pair;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.compat.TelephonyManagerCompat;
 import com.android.contacts.common.util.ContactDisplayUtils;
 import com.android.dialer.DialtactsActivity;
 import com.android.dialer.R;
@@ -172,22 +171,7 @@
         // TODO: Use the photo of contact if all calls are from the same person.
         final int icon = android.R.drawable.stat_notify_voicemail;
 
-        Uri ringtoneUri = null;
-        int notificationDefaults = 0;
-        if (callToNotify != null) {
-            PhoneAccountHandle accountHandle = new PhoneAccountHandle(
-                    ComponentName.unflattenFromString(callToNotify.accountComponentName),
-                    callToNotify.accountId);
-            ringtoneUri = TelephonyManagerCompat
-                    .getVoicemailRingtoneUri(getTelephonyManager(), accountHandle);
-            if (ContactsUtils.FLAG_N_FEATURE) {
-                notificationDefaults = TelephonyManagerCompat.isVoicemailVibrationEnabled(
-                        getTelephonyManager(), accountHandle)
-                        ? Notification.DEFAULT_VIBRATE : 0;
-            } else {
-                notificationDefaults = Notification.DEFAULT_ALL;
-            }
-        }
+        Pair<Uri, Integer> info = getNotificationInfo(callToNotify);
 
         Notification.Builder notificationBuilder = new Notification.Builder(mContext)
                 .setSmallIcon(icon)
@@ -195,8 +179,8 @@
                 .setContentText(callers)
                 .setStyle(new Notification.BigTextStyle().bigText(transcription))
                 .setColor(resources.getColor(R.color.dialer_theme_color))
-                .setSound(ringtoneUri)
-                .setDefaults(notificationDefaults)
+                .setSound(info.first)
+                .setDefaults(info.second)
                 .setDeleteIntent(createMarkNewVoicemailsAsOldIntent())
                 .setAutoCancel(true);
 
@@ -221,6 +205,36 @@
                 notificationBuilder.build());
     }
 
+    /**
+     * Determines which ringtone Uri and Notification defaults to use when updating the notification
+     * for the given call.
+     */
+    private Pair<Uri, Integer> getNotificationInfo(@Nullable NewCall callToNotify) {
+        if (callToNotify == null) {
+            return new Pair<>(null, 0);
+        }
+
+        if (callToNotify.accountComponentName == null || callToNotify.accountId == null) {
+            return new Pair<>(null, Notification.DEFAULT_ALL);
+        }
+
+        PhoneAccountHandle accountHandle = new PhoneAccountHandle(
+                ComponentName.unflattenFromString(callToNotify.accountComponentName),
+                callToNotify.accountId);
+        return new Pair<>(
+                TelephonyManagerCompat.getVoicemailRingtoneUri(
+                        getTelephonyManager(), accountHandle),
+                getNotificationDefaults(accountHandle));
+    }
+
+    private int getNotificationDefaults(PhoneAccountHandle accountHandle) {
+        if (ContactsUtils.FLAG_N_FEATURE) {
+            return TelephonyManagerCompat.isVoicemailVibrationEnabled(getTelephonyManager(),
+                    accountHandle) ? Notification.DEFAULT_VIBRATE : 0;
+        }
+        return Notification.DEFAULT_ALL;
+    }
+
     /** Creates a pending intent that marks all new voicemails as old. */
     private PendingIntent createMarkNewVoicemailsAsOldIntent() {
         Intent intent = new Intent(mContext, CallLogNotificationsService.class);
diff --git a/src/com/android/dialer/settings/AppCompatPreferenceActivity.java b/src/com/android/dialer/settings/AppCompatPreferenceActivity.java
new file mode 100644
index 0000000..4e5d9c9
--- /dev/null
+++ b/src/com/android/dialer/settings/AppCompatPreferenceActivity.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2015 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.dialer.settings;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatDelegate;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
+ * to be used with AppCompat.
+ */
+public class AppCompatPreferenceActivity extends PreferenceActivity {
+    private AppCompatDelegate mDelegate;
+
+    private boolean mIsSafeToCommitTransactions;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        getDelegate().installViewFactory();
+        getDelegate().onCreate(savedInstanceState);
+        super.onCreate(savedInstanceState);
+        mIsSafeToCommitTransactions = true;
+    }
+
+    @Override
+    protected void onPostCreate(Bundle savedInstanceState) {
+        super.onPostCreate(savedInstanceState);
+        getDelegate().onPostCreate(savedInstanceState);
+    }
+
+    public ActionBar getSupportActionBar() {
+        return getDelegate().getSupportActionBar();
+    }
+
+    public void setSupportActionBar(Toolbar toolbar) {
+        getDelegate().setSupportActionBar(toolbar);
+    }
+
+    @Override
+    public MenuInflater getMenuInflater() {
+        return getDelegate().getMenuInflater();
+    }
+
+    @Override
+    public void setContentView(int layoutResID) {
+        getDelegate().setContentView(layoutResID);
+    }
+
+    @Override
+    public void setContentView(View view) {
+        getDelegate().setContentView(view);
+    }
+
+    @Override
+    public void setContentView(View view, ViewGroup.LayoutParams params) {
+        getDelegate().setContentView(view, params);
+    }
+
+    @Override
+    public void addContentView(View view, ViewGroup.LayoutParams params) {
+        getDelegate().addContentView(view, params);
+    }
+
+    @Override
+    protected void onPostResume() {
+        super.onPostResume();
+        getDelegate().onPostResume();
+    }
+
+    @Override
+    protected void onTitleChanged(CharSequence title, int color) {
+        super.onTitleChanged(title, color);
+        getDelegate().setTitle(title);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        getDelegate().onConfigurationChanged(newConfig);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        getDelegate().onStop();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        getDelegate().onDestroy();
+    }
+
+    @Override
+    public void invalidateOptionsMenu() {
+        getDelegate().invalidateOptionsMenu();
+    }
+
+    private AppCompatDelegate getDelegate() {
+        if (mDelegate == null) {
+            mDelegate = AppCompatDelegate.create(this, null);
+        }
+        return mDelegate;
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        mIsSafeToCommitTransactions = true;
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mIsSafeToCommitTransactions = true;
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        mIsSafeToCommitTransactions = false;
+    }
+
+    /**
+     * Returns true if it is safe to commit {@link FragmentTransaction}s at this time, based on
+     * whether {@link Activity#onSaveInstanceState} has been called or not.
+     *
+     * Make sure that the current activity calls into
+     * {@link super.onSaveInstanceState(Bundle outState)} (if that method is overridden),
+     * so the flag is properly set.
+     */
+    public boolean isSafeToCommitTransactions() {
+        return mIsSafeToCommitTransactions;
+    }
+}
diff --git a/src/com/android/dialer/settings/DialerSettingsActivity.java b/src/com/android/dialer/settings/DialerSettingsActivity.java
index b25c5a6..a187157 100644
--- a/src/com/android/dialer/settings/DialerSettingsActivity.java
+++ b/src/com/android/dialer/settings/DialerSettingsActivity.java
@@ -28,7 +28,6 @@
 import android.view.MenuItem;
 import android.widget.Toast;
 
-import com.android.contacts.common.activity.AppCompatPreferenceActivity;
 import com.android.contacts.common.compat.CompatUtils;
 import com.android.contacts.common.compat.SdkVersionOverride;
 import com.android.contacts.common.compat.TelephonyManagerCompat;