Bug 946857 - pre : Expose disabled hosts through Password CP r?nalexander draft
authorvivek <vivekb.balakrishnan@gmail.com>
Tue, 15 Dec 2015 19:23:14 +0200
changeset 331123 1fb7f5141d84acf7aacd985a996f02144816b2b2
parent 331020 b5a5b34ce7d2bee5be119883464bfcad048c4a0e
child 331124 cf314f56271190c64e3016a3ea312ed2cbce5f35
push id10903
push usernalexander@mozilla.com
push dateTue, 16 Feb 2016 00:14:47 +0000
reviewersnalexander
bugs946857
milestone47.0a1
Bug 946857 - pre : Expose disabled hosts through Password CP r?nalexander Added a simple robocop test to verify that it is possible to query disabledHosts with PasswordProviders. MozReview-Commit-ID: K4j4Aczp2xv
mobile/android/base/java/org/mozilla/gecko/db/BrowserContract.java
mobile/android/base/java/org/mozilla/gecko/db/PasswordsProvider.java
mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordProvider.java
--- a/mobile/android/base/java/org/mozilla/gecko/db/BrowserContract.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/BrowserContract.java
@@ -243,16 +243,25 @@ public class BrowserContract {
     }
 
     public static final class DeletedPasswords implements DeletedColumns {
         private DeletedPasswords() {}
         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/deleted-passwords";
         public static final Uri CONTENT_URI = Uri.withAppendedPath(PASSWORDS_AUTHORITY_URI, "deleted-passwords");
     }
 
+    @RobocopTarget
+    public static final class GeckoDisabledHosts {
+        private GeckoDisabledHosts() {}
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/disabled-hosts";
+        public static final Uri CONTENT_URI = Uri.withAppendedPath(PASSWORDS_AUTHORITY_URI, "disabled-hosts");
+
+        public static final String HOSTNAME = "hostname";
+    }
+
     public static final class FormHistory {
         private FormHistory() {}
         public static final Uri CONTENT_URI = Uri.withAppendedPath(FORM_HISTORY_AUTHORITY_URI, "formhistory");
         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/formhistory";
 
         public static final String ID = "id";
         public static final String FIELD_NAME = "fieldname";
         public static final String VALUE = "value";
--- a/mobile/android/base/java/org/mozilla/gecko/db/PasswordsProvider.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/PasswordsProvider.java
@@ -8,16 +8,17 @@ import java.util.HashMap;
 
 import org.mozilla.gecko.CrashHandler;
 import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.GeckoMessageReceiver;
 import org.mozilla.gecko.NSSBridge;
 import org.mozilla.gecko.db.BrowserContract.DeletedPasswords;
+import org.mozilla.gecko.db.BrowserContract.GeckoDisabledHosts;
 import org.mozilla.gecko.db.BrowserContract.Passwords;
 import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.sqlite.MatrixBlobCursor;
 import org.mozilla.gecko.sqlite.SQLiteBridge;
 import org.mozilla.gecko.sync.Utils;
 
 import android.content.ContentValues;
 import android.content.Intent;
@@ -25,29 +26,32 @@ import android.content.UriMatcher;
 import android.database.Cursor;
 import android.net.Uri;
 import android.text.TextUtils;
 import android.util.Log;
 
 public class PasswordsProvider extends SQLiteBridgeContentProvider {
     static final String TABLE_PASSWORDS = "moz_logins";
     static final String TABLE_DELETED_PASSWORDS = "moz_deleted_logins";
+    static final String TABLE_DISABLED_HOSTS = "moz_disabledHosts";
 
     private static final String TELEMETRY_TAG = "SQLITEBRIDGE_PROVIDER_PASSWORDS";
 
     private static final int PASSWORDS = 100;
     private static final int DELETED_PASSWORDS = 101;
+    private static final int DISABLED_HOSTS = 102;
 
     static final String DEFAULT_PASSWORDS_SORT_ORDER = Passwords.HOSTNAME + " ASC";
     static final String DEFAULT_DELETED_PASSWORDS_SORT_ORDER = DeletedPasswords.TIME_DELETED + " ASC";
 
     private static final UriMatcher URI_MATCHER;
 
     private static final HashMap<String, String> PASSWORDS_PROJECTION_MAP;
     private static final HashMap<String, String> DELETED_PASSWORDS_PROJECTION_MAP;
+    private static final HashMap<String, String> DISABLED_HOSTS_PROJECTION_MAP;
 
     // this should be kept in sync with the version in toolkit/components/passwordmgr/storage-mozStorage.js
     private static final int DB_VERSION = 5;
     private static final String DB_FILENAME = "signons.sqlite";
     private static final String WHERE_GUID_IS_NULL = BrowserContract.DeletedPasswords.GUID + " IS NULL";
     private static final String WHERE_GUID_IS_VALUE = BrowserContract.DeletedPasswords.GUID + " = ?";
 
     private static final String LOG_TAG = "GeckoPasswordsProvider";
@@ -77,16 +81,21 @@ public class PasswordsProvider extends S
         PASSWORDS_PROJECTION_MAP.put(Passwords.TIMES_USED, Passwords.TIMES_USED);
 
         URI_MATCHER.addURI(BrowserContract.PASSWORDS_AUTHORITY, "deleted-passwords", DELETED_PASSWORDS);
 
         DELETED_PASSWORDS_PROJECTION_MAP = new HashMap<String, String>();
         DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.ID, DeletedPasswords.ID);
         DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.GUID, DeletedPasswords.GUID);
         DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.TIME_DELETED, DeletedPasswords.TIME_DELETED);
+
+        URI_MATCHER.addURI(BrowserContract.PASSWORDS_AUTHORITY, "disabled-hosts", DISABLED_HOSTS);
+
+        DISABLED_HOSTS_PROJECTION_MAP = new HashMap<String, String>();
+        DISABLED_HOSTS_PROJECTION_MAP.put(GeckoDisabledHosts.HOSTNAME, GeckoDisabledHosts.HOSTNAME);
     }
 
     public PasswordsProvider() {
         super(LOG_TAG);
     }
 
     @Override
     public boolean onCreate() {
@@ -129,31 +138,37 @@ public class PasswordsProvider extends S
 
         switch (match) {
             case PASSWORDS:
                 return Passwords.CONTENT_TYPE;
 
             case DELETED_PASSWORDS:
                 return DeletedPasswords.CONTENT_TYPE;
 
+            case DISABLED_HOSTS:
+                return GeckoDisabledHosts.CONTENT_TYPE;
+
             default:
                 throw new UnsupportedOperationException("Unknown type " + uri);
         }
     }
 
     @Override
     public String getTable(Uri uri) {
         final int match = URI_MATCHER.match(uri);
         switch (match) {
             case DELETED_PASSWORDS:
                 return TABLE_DELETED_PASSWORDS;
 
             case PASSWORDS:
                 return TABLE_PASSWORDS;
 
+            case DISABLED_HOSTS:
+                return TABLE_DISABLED_HOSTS;
+
             default:
                 throw new UnsupportedOperationException("Unknown table " + uri);
         }
     }
 
     @Override
     public String getSortOrder(Uri uri, String aRequested) {
         if (!TextUtils.isEmpty(aRequested)) {
@@ -163,16 +178,19 @@ public class PasswordsProvider extends S
         final int match = URI_MATCHER.match(uri);
         switch (match) {
             case DELETED_PASSWORDS:
                 return DEFAULT_DELETED_PASSWORDS_SORT_ORDER;
 
             case PASSWORDS:
                 return DEFAULT_PASSWORDS_SORT_ORDER;
 
+            case DISABLED_HOSTS:
+                return null;
+
             default:
                 throw new UnsupportedOperationException("Unknown URI " + uri);
         }
     }
 
     @Override
     public void setupDefaults(Uri uri, ContentValues values)
             throws IllegalArgumentException {
@@ -205,16 +223,22 @@ public class PasswordsProvider extends S
                 DBUtils.replaceKey(values, null, Passwords.ENCRYPTED_USERNAME, "");
                 DBUtils.replaceKey(values, null, Passwords.ENCRYPTED_PASSWORD, "");
                 DBUtils.replaceKey(values, null, Passwords.ENC_TYPE, "0");
                 DBUtils.replaceKey(values, null, Passwords.TIME_LAST_USED, nowString);
                 DBUtils.replaceKey(values, null, Passwords.TIME_PASSWORD_CHANGED, nowString);
                 DBUtils.replaceKey(values, null, Passwords.TIMES_USED, "0");
                 break;
 
+            case DISABLED_HOSTS:
+                if (!values.containsKey(GeckoDisabledHosts.HOSTNAME)) {
+                    throw new IllegalArgumentException("Must provide a hostname for a disabled host");
+                }
+                break;
+
             default:
                 throw new UnsupportedOperationException("Unknown URI " + uri);
         }
     }
 
     @Override
     public void initGecko() {
         // We're not in the main process.  The receiver of this Intent can
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordProvider.java
+++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordProvider.java
@@ -1,30 +1,34 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.tests;
 
 import java.io.File;
 
+import org.mozilla.gecko.db.BrowserContract;
+import org.mozilla.gecko.db.BrowserContract.GeckoDisabledHosts;
 import org.mozilla.gecko.db.BrowserContract.Passwords;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 
 /**
  * A basic password contentprovider test.
  * - inserts a password when the database is not yet set up
  * - inserts a password
  * - updates a password
  * - deletes a password
+ * - inserts a disabled host
+ * - queries for disabled host
  */
 public class testPasswordProvider extends BaseTest {
     private static final String DB_NAME = "signons.sqlite";
 
     public void testPasswordProvider() {
         Context context = (Context)getActivity();
         ContentResolver cr = context.getContentResolver();
         ContentValues[] cvs = new ContentValues[1];
@@ -60,16 +64,33 @@ public class testPasswordProvider extend
         c = cr.query(passwordUri, null, null, null, null);
         SqliteCompare(c, cvs);
   
         int numDeleted = cr.delete(passwordUri, null, null);
         mAsserter.is(1, numDeleted, "Correct number deleted");
         cvs = new ContentValues[0];
         c = cr.query(passwordUri, null, null, null, null);
         SqliteCompare(c, cvs);
+
+        ContentValues values = new ContentValues();
+        values.put("hostname", "http://www.example.com");
+
+        // Attempt to insert into the db.
+        Uri disabledHostUri = GeckoDisabledHosts.CONTENT_URI;
+        builder = disabledHostUri.buildUpon();
+        disabledHostUri = builder.appendQueryParameter("profilePath", mProfile).build();
+
+        uri = cr.insert(disabledHostUri, values);
+        expectedUri = disabledHostUri.buildUpon().appendPath("1").build();
+        mAsserter.is(uri.toString(), expectedUri.toString(), "Insert returned correct uri");
+        Cursor cursor = cr.query(disabledHostUri, null, null, null, null);
+        assertNotNull(cursor);
+        assertEquals(1, cursor.getCount());
+        cursor.moveToFirst();
+        CursorMatches(cursor, values);
     }
 
     @Override
     public void tearDown() throws Exception {
         // remove the entire signons.sqlite file
         File profile = new File(mProfile);
         File db = new File(profile, "signons.sqlite");
         if (db.delete()) {