/**
   * * Add or update a cache. CACHE_URL_COL is unique in the table.
   *
   * @param url The url
   * @param c The CacheManager.CacheResult
   */
  void addCache(String url, CacheResult c) {
    assert !JniUtil.useChromiumHttpStack();

    if (url == null || !checkInitialized()) {
      return;
    }

    mCacheInserter.prepareForInsert();
    mCacheInserter.bind(mCacheUrlColIndex, url);
    mCacheInserter.bind(mCacheFilePathColIndex, c.localPath);
    mCacheInserter.bind(mCacheLastModifyColIndex, c.lastModified);
    mCacheInserter.bind(mCacheETagColIndex, c.etag);
    mCacheInserter.bind(mCacheExpiresColIndex, c.expires);
    mCacheInserter.bind(mCacheExpiresStringColIndex, c.expiresString);
    mCacheInserter.bind(mCacheMimeTypeColIndex, c.mimeType);
    mCacheInserter.bind(mCacheEncodingColIndex, c.encoding);
    mCacheInserter.bind(mCacheHttpStatusColIndex, c.httpStatusCode);
    mCacheInserter.bind(mCacheLocationColIndex, c.location);
    mCacheInserter.bind(mCacheContentLengthColIndex, c.contentLength);
    mCacheInserter.bind(mCacheContentDispositionColIndex, c.contentdisposition);
    mCacheInserter.bind(mCacheCrossDomainColIndex, c.crossDomain);
    mCacheInserter.execute();
  }
  private Uri insertInternal(SQLiteDatabase db, Uri uri, ContentValues values) {
    final int match = sUriMatcher.match(uri);
    String id;
    Uri result;
    long longId;

    switch (match) {
      case STOPS:
        // Pull out the Stop ID from the values to construct the new URI
        // (And we'd better have a stop ID)
        id = values.getAsString(ObaContract.Stops._ID);
        if (id == null) {
          throw new IllegalArgumentException("Need a stop ID to insert! " + uri);
        }
        result = Uri.withAppendedPath(ObaContract.Stops.CONTENT_URI, id);
        mStopsInserter.insert(values);
        return result;

      case ROUTES:
        // Pull out the Route ID from the values to construct the new URI
        // (And we'd better have a route ID)
        id = values.getAsString(ObaContract.Routes._ID);
        if (id == null) {
          throw new IllegalArgumentException("Need a routes ID to insert! " + uri);
        }
        result = Uri.withAppendedPath(ObaContract.Routes.CONTENT_URI, id);
        mRoutesInserter.insert(values);
        return result;

      case TRIPS:
        // Pull out the Trip ID from the values to construct the new URI
        // (And we'd better have a trip ID)
        id = values.getAsString(ObaContract.Trips._ID);
        if (id == null) {
          throw new IllegalArgumentException("Need a trip ID to insert! " + uri);
        }
        result = Uri.withAppendedPath(ObaContract.Trips.CONTENT_URI, id);
        mTripsInserter.insert(values);
        return result;

      case TRIP_ALERTS:
        longId = mTripAlertsInserter.insert(values);
        result = ContentUris.withAppendedId(ObaContract.TripAlerts.CONTENT_URI, longId);
        return result;

      case STOP_ROUTE_FILTERS:
        // TODO: We should provide a "virtual" column that is an array,
        // so clients don't have to call the content provider for each item to insert.
        // Pull out the stop ID from the values to construct the new URI
        // (And we'd better have a stop ID)
        id = values.getAsString(ObaContract.StopRouteFilters.STOP_ID);
        if (id == null) {
          throw new IllegalArgumentException("Need a stop ID to insert! " + uri);
        }
        result = Uri.withAppendedPath(ObaContract.StopRouteFilters.CONTENT_URI, id);
        mFilterInserter.insert(values);
        return result;

      case SERVICE_ALERTS:
        // Pull out the Situation ID from the values to construct the new URI
        // (And we'd better have a situation ID)
        id = values.getAsString(ObaContract.ServiceAlerts._ID);
        if (id == null) {
          throw new IllegalArgumentException("Need a situation ID to insert! " + uri);
        }
        result = Uri.withAppendedPath(ObaContract.ServiceAlerts.CONTENT_URI, id);
        mServiceAlertsInserter.insert(values);
        return result;

      case REGIONS:
        longId = mRegionsInserter.insert(values);
        result = ContentUris.withAppendedId(ObaContract.Regions.CONTENT_URI, longId);
        return result;

      case REGION_BOUNDS:
        longId = mRegionBoundsInserter.insert(values);
        result = ContentUris.withAppendedId(ObaContract.RegionBounds.CONTENT_URI, longId);
        return result;

        // What would these mean, anyway??
      case STOPS_ID:
      case ROUTES_ID:
      case TRIPS_ID:
      case TRIP_ALERTS_ID:
      case SERVICE_ALERTS_ID:
      case REGIONS_ID:
      case REGION_BOUNDS_ID:
        throw new UnsupportedOperationException("Cannot insert to this URI: " + uri);
      default:
        throw new IllegalArgumentException("Unknown URI: " + uri);
    }
  }
  private void initCacheDatabase(Context context) {
    assert !JniUtil.useChromiumHttpStack();

    try {
      mCacheDatabase = context.openOrCreateDatabase(CACHE_DATABASE_FILE, 0, null);
    } catch (SQLiteException e) {
      // try again by deleting the old db and create a new one
      if (context.deleteDatabase(CACHE_DATABASE_FILE)) {
        mCacheDatabase = context.openOrCreateDatabase(CACHE_DATABASE_FILE, 0, null);
      }
    }
    mCacheDatabase.enableWriteAheadLogging();

    // mCacheDatabase should not be null,
    // the only case is RequestAPI test has problem to create db
    if (mCacheDatabase == null) {
      mInitialized = true;
      notify();
      return;
    }

    if (mCacheDatabase.getVersion() != CACHE_DATABASE_VERSION) {
      mCacheDatabase.beginTransactionNonExclusive();
      try {
        upgradeCacheDatabase();
        bootstrapCacheDatabase();
        mCacheDatabase.setTransactionSuccessful();
      } finally {
        mCacheDatabase.endTransaction();
      }
      // Erase the files from the file system in the
      // case that the database was updated and the
      // there were existing cache content
      CacheManager.removeAllCacheFiles();
    }

    // use read_uncommitted to speed up READ
    mCacheDatabase.execSQL("PRAGMA read_uncommitted = true;");
    // as only READ can be called in the
    // non-WebViewWorkerThread, and read_uncommitted is used,
    // we can turn off database lock to use transaction.
    mCacheDatabase.setLockingEnabled(false);

    // use InsertHelper for faster insertion
    mCacheInserter = new DatabaseUtils.InsertHelper(mCacheDatabase, "cache");
    mCacheUrlColIndex = mCacheInserter.getColumnIndex(CACHE_URL_COL);
    mCacheFilePathColIndex = mCacheInserter.getColumnIndex(CACHE_FILE_PATH_COL);
    mCacheLastModifyColIndex = mCacheInserter.getColumnIndex(CACHE_LAST_MODIFY_COL);
    mCacheETagColIndex = mCacheInserter.getColumnIndex(CACHE_ETAG_COL);
    mCacheExpiresColIndex = mCacheInserter.getColumnIndex(CACHE_EXPIRES_COL);
    mCacheExpiresStringColIndex = mCacheInserter.getColumnIndex(CACHE_EXPIRES_STRING_COL);
    mCacheMimeTypeColIndex = mCacheInserter.getColumnIndex(CACHE_MIMETYPE_COL);
    mCacheEncodingColIndex = mCacheInserter.getColumnIndex(CACHE_ENCODING_COL);
    mCacheHttpStatusColIndex = mCacheInserter.getColumnIndex(CACHE_HTTP_STATUS_COL);
    mCacheLocationColIndex = mCacheInserter.getColumnIndex(CACHE_LOCATION_COL);
    mCacheContentLengthColIndex = mCacheInserter.getColumnIndex(CACHE_CONTENTLENGTH_COL);
    mCacheContentDispositionColIndex = mCacheInserter.getColumnIndex(CACHE_CONTENTDISPOSITION_COL);
    mCacheCrossDomainColIndex = mCacheInserter.getColumnIndex(CACHE_CROSSDOMAIN_COL);
  }
    private boolean addDefaultBookmarks(SQLiteDatabase db, long parentId, long firstBookmarkId) {
      long bookmarkId = firstBookmarkId;
      Resources res = getContext().getResources();
      final CharSequence[] bookmarks = res.getTextArray(R.array.bookmarks);
      int size = bookmarks.length;
      TypedArray preloads = res.obtainTypedArray(R.array.bookmark_preloads);
      DatabaseUtils.InsertHelper insertHelper = null;
      try {
        insertHelper = new DatabaseUtils.InsertHelper(db, TABLE_BOOKMARKS);
        final int idColumn = insertHelper.getColumnIndex(PartnerBookmarksContract.Bookmarks.ID);
        final int titleColumn =
            insertHelper.getColumnIndex(PartnerBookmarksContract.Bookmarks.TITLE);
        final int urlColumn = insertHelper.getColumnIndex(PartnerBookmarksContract.Bookmarks.URL);
        final int typeColumn = insertHelper.getColumnIndex(PartnerBookmarksContract.Bookmarks.TYPE);
        final int parentColumn =
            insertHelper.getColumnIndex(PartnerBookmarksContract.Bookmarks.PARENT);
        final int faviconColumn =
            insertHelper.getColumnIndex(PartnerBookmarksContract.Bookmarks.FAVICON);
        final int touchiconColumn =
            insertHelper.getColumnIndex(PartnerBookmarksContract.Bookmarks.TOUCHICON);

        for (int i = 0; i + 1 < size; i = i + 2) {
          CharSequence bookmarkDestination = bookmarks[i + 1];

          String bookmarkTitle = bookmarks[i].toString();
          String bookmarkUrl = bookmarkDestination.toString();
          byte[] favicon = null;
          if (i < preloads.length()) {
            int faviconId = preloads.getResourceId(i, 0);
            try {
              favicon = readRaw(res, faviconId);
            } catch (IOException e) {
              Log.i(TAG, "Failed to read favicon for " + bookmarkTitle, e);
            }
          }
          byte[] touchicon = null;
          if (i + 1 < preloads.length()) {
            int touchiconId = preloads.getResourceId(i + 1, 0);
            try {
              touchicon = readRaw(res, touchiconId);
            } catch (IOException e) {
              Log.i(TAG, "Failed to read touchicon for " + bookmarkTitle, e);
            }
          }
          insertHelper.prepareForInsert();
          insertHelper.bind(idColumn, bookmarkId);
          insertHelper.bind(titleColumn, bookmarkTitle);
          insertHelper.bind(urlColumn, bookmarkUrl);
          insertHelper.bind(typeColumn, PartnerBookmarksContract.Bookmarks.BOOKMARK_TYPE_BOOKMARK);
          insertHelper.bind(parentColumn, parentId);
          if (favicon != null) {
            insertHelper.bind(faviconColumn, favicon);
          }
          if (touchicon != null) {
            insertHelper.bind(touchiconColumn, touchicon);
          }
          bookmarkId++;
          if (insertHelper.execute() == -1) {
            Log.i(TAG, "Failed to insert bookmark " + bookmarkTitle);
            return false;
          }
        }
      } finally {
        preloads.recycle();
        insertHelper.close();
      }
      return true;
    }