// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.gsa;
import android.accounts.Account;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.text.TextUtils;
import org.chromium.base.PackageUtils;
import org.chromium.components.signin.ChromeSigninController;
import java.util.List;
/**
* A class responsible fore representing the current state of Chrome's integration with GSA.
*/
public class GSAState {
private static final int GSA_VERSION_FOR_DOCUMENT = 300401021;
private static final int GMS_CORE_VERSION = 6577010;
static final String SEARCH_INTENT_PACKAGE = "com.google.android.googlequicksearchbox";
private static final String GMS_CORE_PACKAGE = "com.google.android.gms";
static final String SEARCH_INTENT_ACTION =
"com.google.android.googlequicksearchbox.TEXT_ASSIST";
/**
* An instance of GSAState class encapsulating knowledge about the current status.
*/
private static GSAState sGSAState;
/**
* The application context to use.
*/
private final Context mContext;
/**
* Caches the result of a computation on whether GSA is available.
*/
private Boolean mGsaAvailable;
/**
* The Google account being used by GSA according to the latest update we have received.
* This may be null.
*/
private String mGsaAccount;
/**
* Returns the singleton instance of GSAState and creates one if necessary.
* @param context The context to use.
* @return The state object.
*/
public static GSAState getInstance(Context context) {
if (sGSAState == null) {
sGSAState = new GSAState(context);
}
return sGSAState;
}
/* Private constructor, since this is a singleton */
private GSAState(Context context) {
mContext = context.getApplicationContext();
}
/**
* Update the GSA logged in account name and whether we are in GSA holdback.
* @param gsaAccount The email address of the logged in account.
*/
public void setGsaAccount(String gsaAccount) {
mGsaAccount = gsaAccount;
}
/**
* @return Whether GSA and Chrome are logged in with the same account. The situation where
* both are logged out is not considered a match.
*/
public boolean doesGsaAccountMatchChrome() {
Account chromeUser = ChromeSigninController.get(mContext).getSignedInUser();
return chromeUser != null && !TextUtils.isEmpty(mGsaAccount) && TextUtils.equals(
chromeUser.name, mGsaAccount);
}
/**
* @return The current GSA account. May return null if GSA hasn't replied yet.
*/
public String getGsaAccount() {
return mGsaAccount;
}
/**
* This is used to check whether GSA package is available to handle search requests and if
* the Chrome experiment to do so is enabled.
* @return Whether the search intent this class creates will resolve to an activity.
*/
public boolean isGsaAvailable() {
if (mGsaAvailable != null) return mGsaAvailable;
mGsaAvailable = false;
PackageManager pm = mContext.getPackageManager();
Intent searchIntent = new Intent(SEARCH_INTENT_ACTION);
searchIntent.setPackage(GSAState.SEARCH_INTENT_PACKAGE);
List<ResolveInfo> resolveInfo = pm.queryIntentActivities(searchIntent, 0);
if (resolveInfo.size() == 0) {
mGsaAvailable = false;
} else if (!isPackageAboveVersion(SEARCH_INTENT_PACKAGE, GSA_VERSION_FOR_DOCUMENT)
|| !isPackageAboveVersion(GMS_CORE_PACKAGE, GMS_CORE_VERSION)) {
mGsaAvailable = false;
} else {
mGsaAvailable = true;
}
return mGsaAvailable;
}
/**
* Check whether the given package meets min requirements for using full document mode.
* @param packageName The package name we are inquiring about.
* @param minVersion The minimum version for the package to be.
* @return Whether the package exists on the device and its version is higher than the minimum
* required version.
*/
private boolean isPackageAboveVersion(String packageName, int minVersion) {
return PackageUtils.getPackageVersion(mContext, packageName) >= minVersion;
}
}