Merge "Use clock's widget as the default keyguard widget" into jb-mr1-lockscreen-dev
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 3ee3c8c..e5e1a2b 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1073,11 +1073,7 @@
             }
             return appWidgetIds;
         }
-        if (appWidgetIdString == null) {
-            return new int[] { LockPatternUtils.ID_DEFAULT_STATUS_WIDGET };
-        } else {
-            return new int[0];
-        }
+        return new int[0];
     }
 
     private static String combineStrings(int[] list, String separator) {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 148560a..3b7d73a 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -404,6 +404,12 @@
     -->
     <integer name="config_longPressOnPowerBehavior">1</integer>
 
+    <!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
+    <string name="widget_default_package_name"></string>
+
+    <!-- Class name for default keyguard appwidget [DO NOT TRANSLATE] -->
+    <string name="widget_default_class_name"></string>
+
     <!-- Indicate whether the SD card is accessible without removing the battery. -->
     <bool name="config_batterySdCardAccessibility">false</bool>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ada2644..06e927b 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2065,15 +2065,6 @@
     <!-- This can be used in any application wanting to disable the text "Emergency number" -->
     <string name="emergency_call_dialog_number_for_display">Emergency number</string>
 
-    <!-- String to display if the clock status widget is selected (it is the default) [CHAR LIMIT=22] -->
-    <string name="widget_default" msgid="8269383575996003796">Clock</string>
-
-    <!-- Package name for default widget [DO NOT TRANSLATE] -->
-    <string name="widget_default_package_name">com.android.deskclock</string>
-
-    <!-- Class name for default widget [DO NOT TRANSLATE] -->
-    <string name="widget_default_class_name">com.android.deskclock.DeskClock</string>
-
     <!--
        *** touch based lock / unlock ***
                                           --> <skip />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 213d93b..3bdf4c6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -479,7 +479,6 @@
   <java-symbol type="string" name="emailTypeOther" />
   <java-symbol type="string" name="emailTypeWork" />
   <java-symbol type="string" name="emergency_call_dialog_number_for_display" />
-  <java-symbol type="string" name="widget_default" />
   <java-symbol type="string" name="widget_default_package_name" />
   <java-symbol type="string" name="widget_default_class_name" />
   <java-symbol type="string" name="emergency_calls_only" />
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index ca3d0a2..18f8b0c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -29,8 +29,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Canvas;
@@ -50,7 +48,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AnimationUtils;
 import android.widget.RemoteViews.OnClickHandler;
 
@@ -59,7 +56,6 @@
 import com.android.internal.widget.LockPatternUtils;
 
 import java.io.File;
-import java.util.ArrayList;
 import java.util.List;
 
 public class KeyguardHostView extends KeyguardViewBase {
@@ -68,10 +64,10 @@
     // Use this to debug all of keyguard
     public static boolean DEBUG = KeyguardViewMediator.DEBUG;
 
-    // also referenced in SecuritySettings.java
     static final int APPWIDGET_HOST_ID = 0x4B455947;
 
     private AppWidgetHost mAppWidgetHost;
+    private AppWidgetManager mAppWidgetManager;
     private KeyguardWidgetPager mAppWidgetContainer;
     private KeyguardSecurityViewFlipper mSecurityViewContainer;
     private KeyguardSelectorView mKeyguardSelectorView;
@@ -113,6 +109,7 @@
         mLockPatternUtils = new LockPatternUtils(context);
         mAppWidgetHost = new AppWidgetHost(
                 context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper());
+        mAppWidgetManager = AppWidgetManager.getInstance(mContext);
         mSecurityModel = new KeyguardSecurityModel(context);
 
         // The following enables the MENU key to work for testing automation
@@ -158,10 +155,6 @@
         mAppWidgetContainer.setCallbacks(mWidgetCallbacks);
         mAppWidgetContainer.setMinScale(0.5f);
 
-        addDefaultWidgets();
-        addWidgetsFromSettings();
-        mSwitchPageRunnable.run();
-
         SlidingChallengeLayout slider =
                 (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
         if (slider != null) {
@@ -183,8 +176,11 @@
             setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
         }
 
-        showPrimarySecurityScreen(false);
+        addDefaultWidgets();
+        addWidgetsFromSettings();
+        mSwitchPageRunnable.run();
 
+        showPrimarySecurityScreen(false);
         updateSecurityViews();
     }
 
@@ -549,8 +545,6 @@
         };
     };
 
-    private KeyguardStatusViewManager mKeyguardStatusViewManager;
-
     // Used to ignore callbacks from methods that are no longer current (e.g. face unlock).
     // This avoids unwanted asynchronous events from messing with the state.
     private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
@@ -715,6 +709,7 @@
         // biometric unlock to start next time keyguard is shown.
         KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
         saveStickyWidgetIndex();
+        checkAppWidgetConsistency();
         showPrimarySecurityScreen(true);
         getSecurityView(mCurrentSecuritySelection).onPause();
         CameraWidgetFrame cameraPage = findCameraPage();
@@ -812,15 +807,16 @@
         }
     }
 
-    private void addWidget(int appId, int pageIndex) {
-        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
-        AppWidgetProviderInfo appWidgetInfo = appWidgetManager.getAppWidgetInfo(appId);
+    private boolean addWidget(int appId, int pageIndex) {
+        AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
         if (appWidgetInfo != null) {
             AppWidgetHostView view = getAppWidgetHost().createView(mContext, appId, appWidgetInfo);
             addWidget(view, pageIndex);
+            return true;
         } else {
             Log.w(TAG, "AppWidgetInfo for app widget id " + appId + " was null, deleting");
             mLockPatternUtils.removeAppWidget(appId);
+            return false;
         }
     }
 
@@ -890,22 +886,7 @@
 
                     @Override
                     public void run() {
-                        int defaultIconId = 0;
-                        Resources res = KeyguardHostView.this.getContext().getResources();
-                        ComponentName clock = new ComponentName(
-                                res.getString(R.string.widget_default_package_name),
-                                res.getString(R.string.widget_default_class_name));
-                        try {
-                            ActivityInfo activityInfo =
-                                    mContext.getPackageManager().getActivityInfo(clock, 0);
-                            if (activityInfo != null) {
-                                defaultIconId = activityInfo.icon;
-                            }
-                        } catch (PackageManager.NameNotFoundException e) {
-                            defaultIconId = 0;
-                        }
-                        launchPickActivityIntent(R.string.widget_default, defaultIconId, clock,
-                                LockPatternUtils.EXTRA_DEFAULT_WIDGET);
+                        launchPickActivityIntent();
                     }
                 });
                 mCallback.dismiss(false);
@@ -916,8 +897,7 @@
         initializeTransportControl();
     }
 
-    private void launchPickActivityIntent(int defaultLabelId, int defaultIconId,
-            ComponentName defaultComponentName, String defaultTag) {
+    private void launchPickActivityIntent() {
         // Create intent to pick widget
         Intent pickIntent = new Intent(AppWidgetManager.ACTION_KEYGUARD_APPWIDGET_PICK);
 
@@ -928,22 +908,6 @@
             pickIntent.putExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER,
                     AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
 
-            // Add an custom entry for the default
-            AppWidgetProviderInfo defaultInfo = new AppWidgetProviderInfo();
-            ArrayList<AppWidgetProviderInfo> extraInfos = new ArrayList<AppWidgetProviderInfo>();
-            defaultInfo.label = getResources().getString(defaultLabelId);
-            defaultInfo.icon = defaultIconId;
-            defaultInfo.provider = defaultComponentName;
-            extraInfos.add(defaultInfo);
-
-            ArrayList<Bundle> extraExtras = new ArrayList<Bundle>();
-            Bundle b = new Bundle();
-            b.putBoolean(defaultTag, true);
-            extraExtras.add(b);
-
-            // Launch the widget picker
-            pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_INFO, extraInfos);
-            pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_EXTRAS, extraExtras);
             pickIntent.putExtra(Intent.EXTRA_INTENT, getBaseIntent());
             pickIntent.addFlags(
                     Intent.FLAG_ACTIVITY_NEW_TASK
@@ -1024,6 +988,22 @@
         }
     }
 
+    private int getAddPageIndex() {
+        View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
+        int addPageIndex = mAppWidgetContainer.indexOfChild(addWidget);
+        // This shouldn't happen, but just to be safe!
+        if (addPageIndex < 0) {
+            addPageIndex = 0;
+        }
+        return addPageIndex;
+    }
+
+    private void addDefaultStatusWidget(int index) {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
+        mAppWidgetContainer.addWidget(statusWidget, index);
+    }
+
     private void addWidgetsFromSettings() {
         DevicePolicyManager dpm =
                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -1036,23 +1016,17 @@
             }
         }
 
-        View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
-        int addPageIndex = mAppWidgetContainer.indexOfChild(addWidget);
-        // This shouldn't happen, but just to be safe!
-        if (addPageIndex < 0) {
-            addPageIndex = 0;
-        }
+        int addPageIndex = getAddPageIndex();
 
         // Add user-selected widget
         final int[] widgets = mLockPatternUtils.getAppWidgets();
+
         if (widgets == null) {
             Log.d(TAG, "Problem reading widgets");
         } else {
             for (int i = widgets.length -1; i >= 0; i--) {
                 if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
-                    LayoutInflater inflater = LayoutInflater.from(mContext);
-                    View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
-                    mAppWidgetContainer.addWidget(statusWidget, addPageIndex + 1);
+                    addDefaultStatusWidget(addPageIndex + 1);
                 } else {
                     // We add the widgets from left to right, starting after the first page after
                     // the add page. We count down, since the order will be persisted from right
@@ -1061,6 +1035,42 @@
                 }
             }
         }
+        checkAppWidgetConsistency();
+    }
+
+    public void checkAppWidgetConsistency() {
+        final int childCount = mAppWidgetContainer.getChildCount();
+        boolean widgetPageExists = false;
+        for (int i = 0; i < childCount; i++) {
+            if (isWidgetPage(i)) {
+                widgetPageExists = true;
+                break;
+            }
+        }
+        if (!widgetPageExists) {
+            final int addPageIndex = getAddPageIndex();
+
+            Resources res = getContext().getResources();
+            ComponentName defaultAppWidget = new ComponentName(
+                    res.getString(R.string.widget_default_package_name),
+                    res.getString(R.string.widget_default_class_name));
+
+            // Note: we don't support configuring the widget
+            int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
+            boolean bindSuccessful = false;
+            try {
+                mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget);
+                bindSuccessful = true;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Error when trying to bind default AppWidget: " + e);
+            }
+            // Use the built-in status/clock view if we can't inflate the default widget
+            if (!(bindSuccessful && addWidget(appWidgetId, addPageIndex + 1))) {
+                addDefaultStatusWidget(addPageIndex + 1);
+            }
+            mAppWidgetContainer.onAddView(
+                    mAppWidgetContainer.getChildAt(addPageIndex + 1), addPageIndex + 1);
+        }
     }
 
     Runnable mSwitchPageRunnable = new Runnable() {
@@ -1155,6 +1165,15 @@
         return null;
     }
 
+    private boolean isWidgetPage(int pageIndex) {
+        View v = mAppWidgetContainer.getChildAt(pageIndex);
+        if (v != null && v instanceof KeyguardWidgetFrame) {
+            KeyguardWidgetFrame kwf = (KeyguardWidgetFrame) v;
+            return kwf.getContentAppWidgetId() != AppWidgetManager.INVALID_APPWIDGET_ID;
+        }
+        return false;
+    }
+
     private boolean isCameraPage(int pageIndex) {
         View v = mAppWidgetContainer.getChildAt(pageIndex);
         return v != null && v instanceof CameraWidgetFrame;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
index b1ff049..bb4272c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
@@ -20,6 +20,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
@@ -220,8 +221,10 @@
         View content = getContent();
         if (content instanceof AppWidgetHostView) {
             return ((AppWidgetHostView) content).getAppWidgetId();
-        } else {
+        } else if (content instanceof KeyguardStatusView) {
             return ((KeyguardStatusView) content).getAppWidgetId();
+        } else {
+            return AppWidgetManager.INVALID_APPWIDGET_ID;
         }
     }
 
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index d0dd9cf..daa82f2 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -599,7 +599,7 @@
     }
 
     public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
-        mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET,
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET,
             "bindAppWidgetId appWidgetId=" + appWidgetId + " provider=" + provider);
         bindAppWidgetIdImpl(appWidgetId, provider, options);
     }
@@ -607,7 +607,7 @@
     public boolean bindAppWidgetIdIfAllowed(
             String packageName, int appWidgetId, ComponentName provider, Bundle options) {
         try {
-            mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET, null);
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET, null);
         } catch (SecurityException se) {
             if (!callerHasBindAppWidgetPermission(packageName)) {
                 return false;