Here are the examples of the java api android.database.ContentObserver taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.
145 Examples
19
Source : SMSHelper.java
with GNU General Public License v2.0
from ZorinOS
with GNU General Public License v2.0
from ZorinOS
/**
* Register a ContentObserver for the Messages database
*
* @param observer ContentObserver to alert on Message changes
*/
public static void registerObserver(@NonNull ContentObserver observer, @NonNull Context context) {
context.getContentResolver().registerContentObserver(SMSHelper.getConversationUri(), true, observer);
}
19
Source : ContactsProvider.java
with GNU General Public License v3.0
from TBog
with GNU General Public License v3.0
from TBog
public clreplaced ContactsProvider extends Provider<ContactEntry> {
private final static String TAG = "ContactsProvider";
private final ContentObserver cObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
// reload contacts
Log.i(TAG, "Contacts changed, reloading provider.");
reload(true);
}
};
public void reload(boolean cancelCurrentLoadTask) {
super.reload(cancelCurrentLoadTask);
if (!isLoaded() && !isLoading())
this.initialize(new LoadContactsEntry(this));
}
@Override
public void onCreate() {
super.onCreate();
// register content observer if we have permission
if (Permission.checkPermission(this, Permission.PERMISSION_READ_CONTACTS)) {
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, false, cObserver);
} else {
Permission.askPermission(Permission.PERMISSION_READ_CONTACTS, new Permission.PermissionResultListener() {
@Override
public void onGranted() {
// Great! Reload the contact provider. We're done :)
reload(true);
}
});
}
}
@Override
public void onDestroy() {
super.onDestroy();
// deregister content observer
getContentResolver().unregisterContentObserver(cObserver);
}
@Override
public void requestResults(String query, Searcher searcher) {
StringNormalizer.Result queryNormalized = StringNormalizer.normalizeWithResult(query, false);
if (queryNormalized.codePoints.length == 0) {
return;
}
FuzzyScore fuzzyScore = new FuzzyScore(queryNormalized.codePoints);
FuzzyScore.MatchInfo matchInfo;
boolean match;
for (ContactEntry pojo : pojos) {
matchInfo = fuzzyScore.match(pojo.normalizedName.codePoints);
match = matchInfo.match;
pojo.setRelevance(pojo.normalizedName, matchInfo);
if (pojo.normalizedNickname != null) {
matchInfo = fuzzyScore.match(pojo.normalizedNickname.codePoints);
if (matchInfo.match && (!match || matchInfo.score > pojo.getRelevance())) {
match = true;
pojo.setRelevance(pojo.normalizedNickname, matchInfo);
}
}
if (!match && queryNormalized.length() > 2) {
// search for the phone number
matchInfo = fuzzyScore.match(pojo.normalizedPhone.codePoints);
match = matchInfo.match;
pojo.setRelevance(pojo.normalizedPhone, matchInfo);
}
if (match) {
int boost = Math.min(30, pojo.timesContacted);
if (pojo.starred) {
boost += 40;
}
pojo.boostRelevance(boost);
if (!searcher.addResult(pojo))
return;
}
}
}
/**
* Find a ContactsPojo from a phoneNumber
* If many contacts match, the one most often contacted will be returned
*
* @param phoneNumber phone number to find (will be normalized)
* @return a contactpojo, or null.
*/
public ContactEntry findByPhone(String phoneNumber) {
StringNormalizer.Result simplifiedPhoneNumber = PhoneNormalizer.simplifyPhoneNumber(phoneNumber);
for (ContactEntry pojo : pojos) {
if (pojo.normalizedPhone.equals(simplifiedPhoneNumber)) {
return pojo;
}
}
return null;
}
}
19
Source : AMapStateListenerImpl.java
with Apache License 2.0
from skyinu
with Apache License 2.0
from skyinu
/**
* 接口实现类
* Created by chen on 2017/1/26.
*/
clreplaced AMapStateListenerImpl implements LocationSource, AMapLocationListener, AMap.OnMapLoadedListener {
/**
* SDK自身的位置变化监听对象
*/
private OnLocationChangedListener mLocationChangedListener;
private AMapStateListener mStateListener;
public AMapStateListenerImpl() {
}
public void setStateListener(@NonNull AMapStateListener stateListener) {
this.mStateListener = stateListener;
}
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
CFLog.i("TAG", "activate");
this.mLocationChangedListener = onLocationChangedListener;
mStateListener.notifyServiceActive();
GlobalApplication.getAppContext().getContentResolver().registerContentObserver(Settings.Secure.getUriFor(android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED), false, mGpsMonitor);
}
@Override
public void deactivate() {
CFLog.i("TAG", "deactivate");
mStateListener.notifyServiceDeactivate();
mLocationChangedListener = null;
mStateListener = null;
GlobalApplication.getAppContext().getContentResolver().unregisterContentObserver(mGpsMonitor);
}
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
CFLog.i("TAG", "onLocationChanged=" + aMapLocation.toString());
if (mLocationChangedListener != null && aMapLocation != null && aMapLocation.getErrorCode() == 0) {
mStateListener.notifyLocationChanged(mLocationChangedListener, aMapLocation);
}
}
@Override
public void onMapLoaded() {
mStateListener.notifyMapLoaded();
}
private final ContentObserver mGpsMonitor = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
mStateListener.notifyGPSSwitchChanged();
}
};
}
19
Source : UserBinaryDictionary.java
with Apache License 2.0
from sergchil
with Apache License 2.0
from sergchil
/**
* An expandable dictionary that stores the words in the user dictionary provider into a binary
* dictionary file to use it from native code.
*/
public clreplaced UserBinaryDictionary extends ExpandableBinaryDictionary {
private static final String TAG = ExpandableBinaryDictionary.clreplaced.getSimpleName();
// The user dictionary provider uses an empty string to mean "all languages".
private static final String USER_DICTIONARY_ALL_LANGUAGES = "";
private static final int HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY = 250;
private static final int LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY = 160;
private static final String[] PROJECTION_QUERY = new String[] { Words.WORD, Words.FREQUENCY };
private static final String NAME = "userunigram";
private ContentObserver mObserver;
final private String mLocaleString;
final private boolean mAlsoUseMoreRestrictiveLocales;
protected UserBinaryDictionary(final Context context, final Locale locale, final boolean alsoUseMoreRestrictiveLocales, final File dictFile, final String name) {
super(context, getDictName(name, locale, dictFile), locale, Dictionary.TYPE_USER, dictFile);
// Catch the error earlier
if (null == locale)
throw new NullPointerException();
final String localeStr = locale.toString();
if (SubtypeLocaleUtils.NO_LANGUAGE.equals(localeStr)) {
// If we don't have a locale, insert into the "all locales" user dictionary.
mLocaleString = USER_DICTIONARY_ALL_LANGUAGES;
} else {
mLocaleString = localeStr;
}
mAlsoUseMoreRestrictiveLocales = alsoUseMoreRestrictiveLocales;
ContentResolver cres = context.getContentResolver();
mObserver = new ContentObserver(null) {
@Override
public void onChange(final boolean self) {
// This hook is deprecated as of API level 16 (Build.VERSION_CODES.JELLY_BEAN),
// but should still be supported for cases where the IME is running on an older
// version of the platform.
onChange(self, null);
}
// The following hook is only available as of API level 16
// (Build.VERSION_CODES.JELLY_BEAN), and as such it will only work on JellyBean+
// devices. On older versions of the platform, the hook above will be called instead.
@Override
public void onChange(final boolean self, final Uri uri) {
setNeedsToRecreate();
}
};
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver);
reloadDictionaryIfRequired();
}
// Note: This method is called by {@link DictionaryFacilitator} using Java reflection.
@ExternallyReferenced
public static UserBinaryDictionary getDictionary(final Context context, final Locale locale, final File dictFile, final String dictNamePrefix, @Nullable final String account) {
return new UserBinaryDictionary(context, locale, false, /* alsoUseMoreRestrictiveLocales */
dictFile, dictNamePrefix + NAME);
}
@Override
public synchronized void close() {
if (mObserver != null) {
mContext.getContentResolver().unregisterContentObserver(mObserver);
mObserver = null;
}
super.close();
}
@Override
public void loadInitialContentsLocked() {
// Split the locale. For example "en" => ["en"], "de_DE" => ["de", "DE"],
// "en_US_foo_bar_qux" => ["en", "US", "foo_bar_qux"] because of the limit of 3.
// This is correct for locale processing.
// For this example, we'll look at the "en_US_POSIX" case.
final String[] localeElements = TextUtils.isEmpty(mLocaleString) ? new String[] {} : mLocaleString.split("_", 3);
final int length = localeElements.length;
final StringBuilder request = new StringBuilder("(locale is NULL)");
String localeSoFar = "";
// At start, localeElements = ["en", "US", "POSIX"] ; localeSoFar = "" ;
// and request = "(locale is NULL)"
for (int i = 0; i < length; ++i) {
// i | localeSoFar | localeElements
// 0 | "" | ["en", "US", "POSIX"]
// 1 | "en_" | ["en", "US", "POSIX"]
// 2 | "en_US_" | ["en", "en_US", "POSIX"]
localeElements[i] = localeSoFar + localeElements[i];
localeSoFar = localeElements[i] + "_";
// i | request
// 0 | "(locale is NULL)"
// 1 | "(locale is NULL) or (locale=?)"
// 2 | "(locale is NULL) or (locale=?) or (locale=?)"
request.append(" or (locale=?)");
}
// At the end, localeElements = ["en", "en_US", "en_US_POSIX"]; localeSoFar = en_US_POSIX_"
// and request = "(locale is NULL) or (locale=?) or (locale=?) or (locale=?)"
final String[] requestArguments;
// If length == 3, we already have all the arguments we need (common prefix is meaningless
// inside variants
if (mAlsoUseMoreRestrictiveLocales && length < 3) {
request.append(" or (locale like ?)");
// The following creates an array with one more (null) position
final String[] localeElementsWithMoreRestrictiveLocalesIncluded = Arrays.copyOf(localeElements, length + 1);
localeElementsWithMoreRestrictiveLocalesIncluded[length] = localeElements[length - 1] + "_%";
requestArguments = localeElementsWithMoreRestrictiveLocalesIncluded;
// If for example localeElements = ["en"]
// then requestArguments = ["en", "en_%"]
// and request = (locale is NULL) or (locale=?) or (locale like ?)
// If localeElements = ["en", "en_US"]
// then requestArguments = ["en", "en_US", "en_US_%"]
} else {
requestArguments = localeElements;
}
final String requestString = request.toString();
addWordsFromProjectionLocked(PROJECTION_QUERY, requestString, requestArguments);
}
private void addWordsFromProjectionLocked(final String[] query, String request, final String[] requestArguments) throws IllegalArgumentException {
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(Words.CONTENT_URI, query, request, requestArguments, null);
addWordsLocked(cursor);
} catch (final SQLiteException e) {
Log.e(TAG, "SQLiteException in the remote User dictionary process.", e);
} finally {
try {
if (null != cursor)
cursor.close();
} catch (final SQLiteException e) {
Log.e(TAG, "SQLiteException in the remote User dictionary process.", e);
}
}
}
private static int scaleFrequencyFromDefaultToLatinIme(final int defaultFrequency) {
// The default frequency for the user dictionary is 250 for historical reasons.
// Latin IME considers a good value for the default user dictionary frequency
// is about 160 considering the scale we use. So we are scaling down the values.
if (defaultFrequency > Integer.MAX_VALUE / LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY) {
return (defaultFrequency / HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY) * LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY;
}
return (defaultFrequency * LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY) / HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY;
}
private void addWordsLocked(final Cursor cursor) {
if (cursor == null)
return;
if (cursor.moveToFirst()) {
final int indexWord = cursor.getColumnIndex(Words.WORD);
final int indexFrequency = cursor.getColumnIndex(Words.FREQUENCY);
while (!cursor.isAfterLast()) {
final String word = cursor.getString(indexWord);
final int frequency = cursor.getInt(indexFrequency);
final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency);
// Safeguard against adding really long words.
if (word.length() <= MAX_WORD_LENGTH) {
runGCIfRequiredLocked(true);
addUnigramLocked(word, adjustedFrequency, false, /* isNotAWord */
false, /* isPossiblyOffensive */
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
}
cursor.moveToNext();
}
}
}
}
19
Source : RadioModel.java
with MIT License
from roadrover
with MIT License
from roadrover
/**
* 收音机数据.
*/
public clreplaced RadioModel {
public static clreplaced Station {
// 名字
public String mName;
// 频率
public int mFreq;
// 频率
public int mKind;
// 波段,取值见{@link IVIRadio#Band}
public int mBand;
//
public int mPosition;
public int mIsLove;
//
public String mDesp;
@Override
public String toString() {
return "mName = " + mName + ", mFreq = " + mFreq + ", mKind = " + mKind + ", mBand = " + mBand + ", mPosition = " + mPosition + ", mIsLove = " + mIsLove + ", mDesp = " + mDesp;
}
}
/**
* 获取收音机站台频率列表,该方法时直接获取收音机数据库的数据
*
* @param context
* @return
*/
public static List<RadioModel.Station> getStationList(Context context) {
List<RadioModel.Station> stations = new ArrayList<>();
if (context != null && checkValidProvider(Provider.TableColumns.CONTENT_URI, context)) {
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(Provider.TableColumns.CONTENT_URI, new String[] { Provider.TableColumns.KEY_ID, Provider.TableColumns.KEY_NAME, Provider.TableColumns.KEY_FREQ, Provider.TableColumns.KEY_DESP, Provider.TableColumns.KEY_BAND, Provider.TableColumns.KEY_KIND, Provider.TableColumns.KEY_POSITION, Provider.TableColumns.KEY_ISLOVE }, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
do {
// 获取收音机站台频率数据
RadioModel.Station station = new RadioModel.Station();
station.mName = cursor.getString(cursor.getColumnIndex(Provider.TableColumns.KEY_NAME));
station.mFreq = cursor.getInt(cursor.getColumnIndex(Provider.TableColumns.KEY_FREQ));
station.mDesp = cursor.getString(cursor.getColumnIndex(Provider.TableColumns.KEY_DESP));
station.mBand = cursor.getInt(cursor.getColumnIndex(Provider.TableColumns.KEY_BAND));
station.mKind = cursor.getInt(cursor.getColumnIndex(Provider.TableColumns.KEY_KIND));
station.mPosition = cursor.getInt(cursor.getColumnIndex(Provider.TableColumns.KEY_POSITION));
station.mIsLove = cursor.getInt(cursor.getColumnIndex(Provider.TableColumns.KEY_ISLOVE));
stations.add(station);
Logcat.d("station = " + station.toString());
} while (cursor.moveToNext());
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
cursor = null;
}
}
}
return stations;
}
public interface ModelListener {
void onChange(List<RadioModel.Station> stations);
}
private static ContentObserver mContentObserver = null;
/**
* 监听收音站台频率的接口,语音等应用需要知道收音站台频率发生改变
*
* @param context
* @param listener
*/
public static void registerStationListener(final Context context, final ModelListener listener) {
if (context != null && listener != null) {
if (mContentObserver != null) {
return;
}
mContentObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
Logcat.d("selfChange:" + selfChange);
if (!selfChange) {
if (listener != null) {
listener.onChange(getStationList(context));
}
}
}
};
context.getContentResolver().registerContentObserver(Provider.TableColumns.CONTENT_URI, false, mContentObserver);
}
}
/**
* 不再监听收音站台频率的改变消息
*
* @param context
*/
public static void unregisterStationListener(Context context) {
if (context != null && mContentObserver != null) {
context.getContentResolver().unregisterContentObserver(mContentObserver);
mContentObserver = null;
}
}
/**
* 检测这个contentprovider是否合法
*
* @param uri
* @return 合法返回true, 否则返回false
*/
private static boolean checkValidProvider(Uri uri, Context context) {
if (null == context) {
return false;
}
ContentProviderClient client = context.getContentResolver().acquireContentProviderClient(uri);
if (null == client) {
return false;
} else {
client.release();
return true;
}
}
}
19
Source : BluetoothModel.java
with MIT License
from roadrover
with MIT License
from roadrover
/**
* 获取蓝牙应用里面的数据.
* 可以获取到电话本的数据,主要方式是通过aidl连接蓝牙app的数据库
* 注:要使用该类,必须你的蓝牙app,要实现联系人数据库的ContentProvider
*/
public clreplaced BluetoothModel {
/**
* 联系人定义类
*/
public static clreplaced Contact {
// 名字
public String mName;
// 电话号码
public String mPhoneNumber;
@Override
public String toString() {
return "Contact{" + "mName='" + mName + '\'' + ", mPhoneNumber='" + mPhoneNumber + '\'' + '}';
}
}
/**
* 历史记录定义类
*/
public static clreplaced CallHistory {
// 状态
public int mStatus = 0;
// 名字
public String mName = "";
// 电话号码
public String mPhoneNumber = "";
// 显示时间
public String mTime = "";
// 排序
public String mSort = "";
@Override
public String toString() {
return "CallHistory{" + "mStatus=" + mStatus + ", mName='" + mName + '\'' + ", mPhoneNumber='" + mPhoneNumber + '\'' + ", mTime='" + mTime + '\'' + ", mSort='" + mSort + '\'' + '}';
}
}
/**
* 蓝牙电话表格
*/
public static clreplaced BluetoothTable {
/**
* 联系人表格
*/
public static final String TABLE_CONTACT = "tbl_stPhoneBook";
/**
* 通话记录表格
*/
public static final String TABLE_CALL_HISTORY = "tbl_stCallHistory";
}
/**
* 联系人的ContentProvider的数据接口
*/
public static clreplaced Provider {
public static final String AUTHORITY = "com.roadrover.bluetooth";
public static final Uri URI = Uri.parse("content://" + AUTHORITY + "/" + BluetoothTable.TABLE_CONTACT);
/**
* 通话记录表
*/
public static final Uri URI_CALL_HISTORY = Uri.parse("content://" + AUTHORITY + "/" + BluetoothTable.TABLE_CALL_HISTORY);
private static final String KEY_STATUS = "status";
private static final String KEY_NAME = "name";
private static final String KEY_PHONE_NUMBER = "phoneNumber";
private static final String KEY_TIME = "time";
private static final String KEY_SORT = "sort";
private static final String KEY_ADDR = "addr";
}
// 判断两个电话号码是否一样,只判断最后7位
private static final int EQUALS_PHONE_NUMBER_COUNT = 7;
/**
* 获取蓝牙历史通话记录列表,该方法时直接获取蓝牙联系数据库的数据,不是从串口获取
* @param context 上下文
* @param address 蓝牙设备地址
* @return 返回历史通话记录列表
*/
public static List<CallHistory> getCallHistoryList(Context context, String address) {
List<CallHistory> callHistorys = new ArrayList<>();
if (context != null && checkValidProvider(Provider.URI_CALL_HISTORY, context)) {
Cursor cursor = null;
try {
String selection = Provider.KEY_ADDR + "=?";
String[] selectionArgs = new String[] { address };
cursor = context.getContentResolver().query(Provider.URI_CALL_HISTORY, new String[] { Provider.KEY_STATUS, Provider.KEY_NAME, Provider.KEY_PHONE_NUMBER, Provider.KEY_TIME, Provider.KEY_SORT }, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
do {
// 获取蓝牙联系人数据
CallHistory callHistory = new CallHistory();
callHistory.mStatus = cursor.getInt(cursor.getColumnIndex(Provider.KEY_STATUS));
callHistory.mName = cursor.getString(cursor.getColumnIndex(Provider.KEY_NAME));
callHistory.mPhoneNumber = cursor.getString(cursor.getColumnIndex(Provider.KEY_PHONE_NUMBER));
callHistory.mTime = cursor.getString(cursor.getColumnIndex(Provider.KEY_TIME));
callHistory.mSort = cursor.getString(cursor.getColumnIndex(Provider.KEY_SORT));
callHistorys.add(callHistory);
} while (cursor.moveToNext());
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
cursor = null;
}
}
}
return callHistorys;
}
/**
* 获取蓝牙联系人列表,该方法时直接获取蓝牙联系数据库的数据,不是从串口获取
* @param context 上下文
* @return 返回当前联系人列表
*/
public static List<Contact> getContactList(Context context) {
List<Contact> contacts = new ArrayList<>();
if (context != null && checkValidProvider(Provider.URI, context)) {
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(Provider.URI, new String[] { Provider.KEY_NAME, Provider.KEY_PHONE_NUMBER }, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
do {
// 获取蓝牙联系人数据
Contact contact = new Contact();
contact.mName = cursor.getString(cursor.getColumnIndex(Provider.KEY_NAME));
contact.mPhoneNumber = cursor.getString(cursor.getColumnIndex(Provider.KEY_PHONE_NUMBER));
contacts.add(contact);
} while (cursor.moveToNext());
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
cursor = null;
}
}
}
return contacts;
}
/**
* 通过电话号码,获取联系人名字
* @param phoneNumber 电话号码
* @param contacts 联系人列表
* @return 返回联系人名字
*/
public static String getContactName(String phoneNumber, List<Contact> contacts) {
if (!ListUtils.isEmpty(contacts) && !TextUtils.isEmpty(phoneNumber)) {
for (Contact contact : contacts) {
if (isPhoneNumberEquals(phoneNumber, contact.mPhoneNumber)) {
return contact.mName;
}
}
}
return "";
}
/**
* 判断两个电话号码是否完全相等
* @param src 源电话号码
* @param dest 目标电话号码
* @return 相等返回true,否则返回false
*/
public static boolean isPhoneNumberEquals(String src, String dest) {
if (src != null && dest != null) {
String srcCompare = src.replace(" ", "");
// 去掉空格之后再比较
String destCompare = dest.replace(" ", "");
if (TextUtils.equals(srcCompare, destCompare)) {
// 完全相等
return true;
}
// 有些地区会在前面+86等,所以只判断最后7位
if (srcCompare.length() >= EQUALS_PHONE_NUMBER_COUNT && destCompare.length() >= EQUALS_PHONE_NUMBER_COUNT) {
String lastNumberCount = destCompare.substring(destCompare.length() - EQUALS_PHONE_NUMBER_COUNT);
if (srcCompare.endsWith(lastNumberCount)) {
return true;
}
}
}
return false;
}
/**
* 监听数据库的改变接口定义
*/
public interface ModelListener {
void onChange(List<Contact> contacts);
}
/**
* 监听数据库的改变接口定义
*/
public interface ModelCallHistoryListener {
void onChange();
}
private static ContentObserver mContentObserver = null;
private static ContentObserver mCallHistoryObserver = null;
/**
* 监听下载联系人的接口,语音等应用需要知道蓝牙联系人发生改变
* @param context
* @param listener
*/
public static void registerContactListener(final Context context, final ModelListener listener) {
if (context != null && listener != null) {
if (mContentObserver != null) {
return;
}
mContentObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
Logcat.d("selfChange:" + selfChange);
if (!selfChange) {
if (listener != null) {
listener.onChange(getContactList(context));
}
}
}
};
context.getContentResolver().registerContentObserver(Provider.URI, false, mContentObserver);
}
}
/**
* 监听通话记录数据改变
*
* @param context
* @param listener
*/
public static void registerCallHistoryListener(final Context context, final ModelCallHistoryListener listener) {
if (context != null && listener != null) {
if (mCallHistoryObserver != null) {
return;
}
mCallHistoryObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
Logcat.d("selfChange:" + selfChange);
if (!selfChange) {
if (listener != null) {
listener.onChange();
}
}
}
};
context.getContentResolver().registerContentObserver(Provider.URI_CALL_HISTORY, false, mCallHistoryObserver);
}
}
/**
* 不再监听联系人的改变消息
* @param context
*/
public static void unregisterContactListener(Context context) {
if (context != null && mContentObserver != null) {
context.getContentResolver().unregisterContentObserver(mContentObserver);
mContentObserver = null;
}
}
/**
* 不再监听通话记录的改变消息
*
* @param context
*/
public static void unregisterCallHistoryListener(Context context) {
if (context != null && mCallHistoryObserver != null) {
context.getContentResolver().unregisterContentObserver(mCallHistoryObserver);
mCallHistoryObserver = null;
}
}
/**
* 检测这个contentprovider是否合法
*
* @param uri
* @return 合法返回true,否则返回false
*/
private static boolean checkValidProvider(Uri uri, Context context) {
if (null == context) {
return false;
}
ContentProviderClient client = context.getContentResolver().acquireContentProviderClient(uri);
if (null == client) {
return false;
} else {
client.release();
return true;
}
}
}
19
Source : UserDictionary.java
with GNU General Public License v3.0
from PhilippC
with GNU General Public License v3.0
from PhilippC
public clreplaced UserDictionary extends ExpandableDictionary {
private static final String[] PROJECTION = { Words._ID, Words.WORD, Words.FREQUENCY };
private static final int INDEX_WORD = 1;
private static final int INDEX_FREQUENCY = 2;
private ContentObserver mObserver;
private String mLocale;
public UserDictionary(Context context, String locale) {
super(context, Suggest.DIC_USER);
mLocale = locale;
// Perform a managed query. The Activity will handle closing and requerying the cursor
// when needed.
ContentResolver cres = context.getContentResolver();
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver = new ContentObserver(null) {
@Override
public void onChange(boolean self) {
setRequiresReload(true);
}
});
loadDictionary();
}
@Override
public synchronized void close() {
if (mObserver != null) {
getContext().getContentResolver().unregisterContentObserver(mObserver);
mObserver = null;
}
super.close();
}
@Override
public void loadDictionaryAsync() {
// Cursor cursor = getContext().getContentResolver()
// .query(Words.CONTENT_URI, PROJECTION, "(locale IS NULL) or (locale=?)",
// new String[] { mLocale }, null);
// addWords(cursor);
}
/**
* Adds a word to the dictionary and makes it persistent.
* @param word the word to add. If the word is capitalized, then the dictionary will
* recognize it as a capitalized word when searched.
* @param frequency the frequency of occurrence of the word. A frequency of 255 is considered
* the highest.
* @TODO use a higher or float range for frequency
*/
@Override
public synchronized void addWord(String word, int frequency) {
// Force load the dictionary here synchronously
if (getRequiresReload())
loadDictionaryAsync();
// Safeguard against adding long words. Can cause stack overflow.
if (word.length() >= getMaxWordLength())
return;
super.addWord(word, frequency);
// Update the user dictionary provider
final ContentValues values = new ContentValues(5);
values.put(Words.WORD, word);
values.put(Words.FREQUENCY, frequency);
values.put(Words.LOCALE, mLocale);
values.put(Words.APP_ID, 0);
final ContentResolver contentResolver = getContext().getContentResolver();
new Thread("addWord") {
public void run() {
contentResolver.insert(Words.CONTENT_URI, values);
}
}.start();
// In case the above does a synchronous callback of the change observer
setRequiresReload(false);
}
@Override
public synchronized void getWords(final WordComposer codes, final WordCallback callback, int[] nextLettersFrequencies) {
super.getWords(codes, callback, nextLettersFrequencies);
}
@Override
public synchronized boolean isValidWord(CharSequence word) {
return super.isValidWord(word);
}
private void addWords(Cursor cursor) {
clearDictionary();
final int maxWordLength = getMaxWordLength();
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
String word = cursor.getString(INDEX_WORD);
int frequency = cursor.getInt(INDEX_FREQUENCY);
// Safeguard against adding really long words. Stack may overflow due
// to recursion
if (word.length() < maxWordLength) {
super.addWord(word, frequency);
}
cursor.moveToNext();
}
}
cursor.close();
}
}
19
Source : ContactsDictionary.java
with GNU General Public License v3.0
from PhilippC
with GNU General Public License v3.0
from PhilippC
public clreplaced ContactsDictionary extends ExpandableDictionary {
private static final String[] PROJECTION = { Contacts._ID, Contacts.DISPLAY_NAME };
private static final String TAG = "ContactsDictionary";
/**
* Frequency for contacts information into the dictionary
*/
private static final int FREQUENCY_FOR_CONTACTS = 128;
private static final int FREQUENCY_FOR_CONTACTS_BIGRAM = 90;
private static final int INDEX_NAME = 1;
private ContentObserver mObserver;
private long mLastLoadedContacts;
public ContactsDictionary(Context context, int dicTypeId) {
super(context, dicTypeId);
// Perform a managed query. The Activity will handle closing and requerying the cursor
// when needed.
ContentResolver cres = context.getContentResolver();
cres.registerContentObserver(Contacts.CONTENT_URI, true, mObserver = new ContentObserver(null) {
@Override
public void onChange(boolean self) {
setRequiresReload(true);
}
});
loadDictionary();
}
@Override
public synchronized void close() {
if (mObserver != null) {
getContext().getContentResolver().unregisterContentObserver(mObserver);
mObserver = null;
}
super.close();
}
@Override
public void startDictionaryLoadingTaskLocked() {
long now = SystemClock.uptimeMillis();
if (mLastLoadedContacts == 0 || now - mLastLoadedContacts > 30 * 60 * 1000) /* 30 minutes */
{
super.startDictionaryLoadingTaskLocked();
}
}
@Override
public void loadDictionaryAsync() {
/*try {
Cursor cursor = getContext().getContentResolver()
.query(Contacts.CONTENT_URI, PROJECTION, null, null, null);
if (cursor != null) {
addWords(cursor);
}
} catch(IllegalStateException e) {
Log.e(TAG, "Contacts DB is having problems");
}
mLastLoadedContacts = SystemClock.uptimeMillis();*/
}
private void addWords(Cursor cursor) {
clearDictionary();
final int maxWordLength = getMaxWordLength();
try {
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
String name = cursor.getString(INDEX_NAME);
if (name != null) {
int len = name.length();
String prevWord = null;
// TODO: Better tokenization for non-Latin writing systems
for (int i = 0; i < len; i++) {
if (Character.isLetter(name.charAt(i))) {
int j;
for (j = i + 1; j < len; j++) {
char c = name.charAt(j);
if (!(c == '-' || c == '\'' || Character.isLetter(c))) {
break;
}
}
String word = name.substring(i, j);
i = j - 1;
// Safeguard against adding really long words. Stack
// may overflow due to recursion
// Also don't add single letter words, possibly confuses
// capitalization of i.
final int wordLen = word.length();
if (wordLen < maxWordLength && wordLen > 1) {
super.addWord(word, FREQUENCY_FOR_CONTACTS);
if (!TextUtils.isEmpty(prevWord)) {
// TODO Do not add email address
// Not so critical
super.setBigram(prevWord, word, FREQUENCY_FOR_CONTACTS_BIGRAM);
}
prevWord = word;
}
}
}
}
cursor.moveToNext();
}
}
cursor.close();
} catch (IllegalStateException e) {
Log.e(TAG, "Contacts DB is having problems");
}
}
}
19
Source : SettingsCursor.java
with GNU General Public License v3.0
from MuntashirAkon
with GNU General Public License v3.0
from MuntashirAkon
@Override
public void unregisterContentObserver(ContentObserver contentObserver) {
if (cursor != null)
cursor.unregisterContentObserver(contentObserver);
}
19
Source : ObservingLiveData.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
/**
* Implementation of {@link androidx.lifecycle.LiveData} that will handle closing the contained
* {@link Closeable} when the value changes.
*/
public clreplaced ObservingLiveData<E extends ObservableContent> extends MutableLiveData<E> {
private ContentObserver observer;
@Override
public void setValue(E value) {
E previous = getValue();
if (previous != null) {
previous.unregisterContentObserver(observer);
StreamUtil.close(previous);
}
value.registerContentObserver(observer);
super.setValue(value);
}
public void close() {
E value = getValue();
if (value != null) {
value.unregisterContentObserver(observer);
StreamUtil.close(value);
}
}
public void registerContentObserver(@NonNull ContentObserver observer) {
this.observer = observer;
}
}
19
Source : ObservingLiveData.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
public void registerContentObserver(@NonNull ContentObserver observer) {
this.observer = observer;
}
19
Source : MediaDatabase.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
public void unsubscribeToMediaChanges(@NonNull ContentObserver observer) {
context.getContentResolver().unregisterContentObserver(observer);
}
19
Source : MediaDatabase.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
public void subscribeToMediaChanges(@NonNull ContentObserver observer) {
registerAttachmentListeners(observer);
}
19
Source : VideoActivity.java
with Apache License 2.0
from komamj
with Apache License 2.0
from komamj
/**
* Created by koma on 11/28/16.
*/
public clreplaced VideoActivity extends BaseMenuActivity {
private static final String TAG = "VideoActivity";
private VideoContract.Presenter mPresenter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LogUtils.i(TAG, "onCreate");
init();
}
private void init() {
VideoFragment videoFragment = (VideoFragment) getSupportFragmentManager().findFragmentById(R.id.content);
if (videoFragment == null) {
videoFragment = new VideoFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.content, videoFragment).commit();
}
mPresenter = new VideoPresenter(videoFragment, FileRepository.getInstance());
mPresenter.subscribe();
getContentResolver().registerContentObserver(FileCategoryUtils.getAudioUri(), true, mVideoObserver);
}
private final ContentObserver mVideoObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
LogUtils.i(TAG, "Video uri change so refresh");
if (mPresenter != null) {
mPresenter.getVideoFiles();
}
}
};
@Override
public void onStart() {
super.onStart();
LogUtils.i(TAG, "onStart");
}
@Override
public void onResume() {
super.onResume();
LogUtils.i(TAG, "onResume");
}
@Override
public void onPause() {
super.onPause();
LogUtils.i(TAG, "onPause");
}
@Override
public void onStop() {
super.onStop();
LogUtils.i(TAG, "onStop");
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtils.i(TAG, "onDestroy");
}
@Override
protected int getLayoutId() {
return R.layout.common_layout;
}
@Override
protected void sortByType() {
LogUtils.i(TAG, "sortByType");
}
@Override
protected void sortByName() {
LogUtils.i(TAG, "sortByName");
}
@Override
protected void sortBySize() {
LogUtils.i(TAG, "sortBySize");
}
@Override
protected void sortByDate() {
LogUtils.i(TAG, "sortByDate");
}
}
19
Source : AudioActivity.java
with Apache License 2.0
from komamj
with Apache License 2.0
from komamj
/**
* Created by koma on 11/19/16.
*/
public clreplaced AudioActivity extends BaseMenuActivity {
private static final String TAG = "AudioActivity";
AudioPresenter mPresenter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LogUtils.i(TAG, "onCreate");
init();
}
private void init() {
AudioFragment audioFragment = (AudioFragment) getSupportFragmentManager().findFragmentById(R.id.content);
if (audioFragment == null) {
audioFragment = new AudioFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.content, audioFragment).commit();
}
mPresenter = new AudioPresenter(audioFragment, FileRepository.getInstance());
getContentResolver().registerContentObserver(FileCategoryUtils.getAudioUri(), true, mAudioObserver);
}
private final ContentObserver mAudioObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
LogUtils.i(TAG, "Audio uri change so refresh");
if (mPresenter != null) {
mPresenter.getAudioFiles();
}
}
};
@Override
public void onStart() {
super.onStart();
LogUtils.i(TAG, "onStart");
}
@Override
public void onResume() {
super.onResume();
LogUtils.i(TAG, "onResume");
}
@Override
public void onPause() {
super.onPause();
LogUtils.i(TAG, "onPause");
}
@Override
public void onStop() {
super.onStop();
LogUtils.i(TAG, "onStop");
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtils.i(TAG, "onDestroy");
if (mAudioObserver != null) {
getContentResolver().unregisterContentObserver(mAudioObserver);
}
}
@Override
protected int getLayoutId() {
return R.layout.common_layout;
}
@Override
protected void sortByType() {
}
@Override
protected void sortByName() {
}
@Override
protected void sortBySize() {
}
@Override
protected void sortByDate() {
}
}
19
Source : SettingsFragment.java
with Apache License 2.0
from KeikaiLauncher
with Apache License 2.0
from KeikaiLauncher
public clreplaced SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
/**
* This field generates a ContentObserver to enable or disable the orientation locked setting depending if
* rotation is locked or unlocked.
*/
private final ContentObserver mAccSettingObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
final Preference orientationPreference = findPreference(R.string.pref_key_allow_rotation);
orientationPreference.setEnabled(isOrientationLocked());
super.onChange(selfChange);
}
};
/**
* This method returns whether the system orientation is locked.
*
* @return True if orientation is locked, false otherwise.
*/
private boolean isOrientationLocked() {
return Settings.System.getInt(getPreferenceScreen().getContext().getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1;
}
private Preference findPreference(@StringRes final int prefKey) {
return findPreference(getString(prefKey));
}
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
findPreference(R.string.pref_key_notification_priority).setEnabled(false);
}
setUsageStatisticsStatus();
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onPause() {
final PreferenceScreen prefs = getPreferenceScreen();
prefs.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
prefs.getContext().getContentResolver().unregisterContentObserver(mAccSettingObserver);
super.onPause();
}
@Override
public void onResume() {
super.onResume();
final Preference orientationPreference = findPreference(R.string.pref_key_allow_rotation);
final Context context = orientationPreference.getContext();
final Uri accUri = Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION);
context.getContentResolver().registerContentObserver(accUri, false, mAccSettingObserver);
orientationPreference.setEnabled(isOrientationLocked());
orientationPreference.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
final Context context = getPreferenceScreen().getContext();
// Fragments suck.
if (context != null) {
final SharedLauncherPrefs prefs = new SharedLauncherPrefs(context);
if (key.equals(getString(R.string.pref_key_notification)) || key.equals(getString(R.string.pref_key_notification_priority))) {
ShortcutNotificationManager.cancelNotification(context);
if (prefs.isNotificationEnabled()) {
ShortcutNotificationManager.showNotification(context);
}
}
}
}
/**
* This method sets the usage statistics preference status by checking the availability of the
* UsageStats subsystem.
*/
private void setUsageStatisticsStatus() {
final Preference pref = findPreference(R.string.pref_key_modify_usage_statistics);
final PackageManager pm = pref.getContext().getPackageManager();
pref.setEnabled(pref.getIntent().resolveActivity(pm) != null);
}
}
19
Source : UserBinaryDictionary.java
with GNU General Public License v3.0
from dslul
with GNU General Public License v3.0
from dslul
/**
* An expandable dictionary that stores the words in the user dictionary provider into a binary
* dictionary file to use it from native code.
*/
public clreplaced UserBinaryDictionary extends ExpandableBinaryDictionary {
private static final String TAG = ExpandableBinaryDictionary.clreplaced.getSimpleName();
// The user dictionary provider uses an empty string to mean "all languages".
private static final String USER_DICTIONARY_ALL_LANGUAGES = "";
private static final int HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY = 250;
private static final int LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY = 160;
// Shortcut frequency is 0~15, with 15 = whitelist. We don't want user dictionary entries
// to auto-correct, so we set this to the highest frequency that won't, i.e. 14.
private static final int USER_DICT_SHORTCUT_FREQUENCY = 14;
private static final String[] PROJECTION_QUERY_WITH_SHORTCUT = new String[] { Words.WORD, Words.SHORTCUT, Words.FREQUENCY };
private static final String[] PROJECTION_QUERY_WITHOUT_SHORTCUT = new String[] { Words.WORD, Words.FREQUENCY };
private static final String NAME = "userunigram";
private ContentObserver mObserver;
final private String mLocaleString;
final private boolean mAlsoUseMoreRestrictiveLocales;
protected UserBinaryDictionary(final Context context, final Locale locale, final boolean alsoUseMoreRestrictiveLocales, final File dictFile, final String name) {
super(context, getDictName(name, locale, dictFile), locale, Dictionary.TYPE_USER, dictFile);
// Catch the error earlier
if (null == locale)
throw new NullPointerException();
final String localeStr = locale.toString();
if (SubtypeLocaleUtils.NO_LANGUAGE.equals(localeStr)) {
// If we don't have a locale, insert into the "all locales" user dictionary.
mLocaleString = USER_DICTIONARY_ALL_LANGUAGES;
} else {
mLocaleString = localeStr;
}
mAlsoUseMoreRestrictiveLocales = alsoUseMoreRestrictiveLocales;
ContentResolver cres = context.getContentResolver();
mObserver = new ContentObserver(null) {
@Override
public void onChange(final boolean self) {
// This hook is deprecated as of API level 16 (Build.VERSION_CODES.JELLY_BEAN),
// but should still be supported for cases where the IME is running on an older
// version of the platform.
onChange(self, null);
}
// The following hook is only available as of API level 16
// (Build.VERSION_CODES.JELLY_BEAN), and as such it will only work on JellyBean+
// devices. On older versions of the platform, the hook above will be called instead.
@Override
public void onChange(final boolean self, final Uri uri) {
setNeedsToRecreate();
}
};
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver);
reloadDictionaryIfRequired();
}
// Note: This method is called by {@link DictionaryFacilitator} using Java reflection.
@ExternallyReferenced
public static UserBinaryDictionary getDictionary(final Context context, final Locale locale, final File dictFile, final String dictNamePrefix, @Nullable final String account) {
return new UserBinaryDictionary(context, locale, false, /* alsoUseMoreRestrictiveLocales */
dictFile, dictNamePrefix + NAME);
}
@Override
public synchronized void close() {
if (mObserver != null) {
mContext.getContentResolver().unregisterContentObserver(mObserver);
mObserver = null;
}
super.close();
}
@Override
public void loadInitialContentsLocked() {
// Split the locale. For example "en" => ["en"], "de_DE" => ["de", "DE"],
// "en_US_foo_bar_qux" => ["en", "US", "foo_bar_qux"] because of the limit of 3.
// This is correct for locale processing.
// For this example, we'll look at the "en_US_POSIX" case.
final String[] localeElements = TextUtils.isEmpty(mLocaleString) ? new String[] {} : mLocaleString.split("_", 3);
final int length = localeElements.length;
final StringBuilder request = new StringBuilder("(locale is NULL)");
String localeSoFar = "";
// At start, localeElements = ["en", "US", "POSIX"] ; localeSoFar = "" ;
// and request = "(locale is NULL)"
for (int i = 0; i < length; ++i) {
// i | localeSoFar | localeElements
// 0 | "" | ["en", "US", "POSIX"]
// 1 | "en_" | ["en", "US", "POSIX"]
// 2 | "en_US_" | ["en", "en_US", "POSIX"]
localeElements[i] = localeSoFar + localeElements[i];
localeSoFar = localeElements[i] + "_";
// i | request
// 0 | "(locale is NULL)"
// 1 | "(locale is NULL) or (locale=?)"
// 2 | "(locale is NULL) or (locale=?) or (locale=?)"
request.append(" or (locale=?)");
}
// At the end, localeElements = ["en", "en_US", "en_US_POSIX"]; localeSoFar = en_US_POSIX_"
// and request = "(locale is NULL) or (locale=?) or (locale=?) or (locale=?)"
final String[] requestArguments;
// If length == 3, we already have all the arguments we need (common prefix is meaningless
// inside variants
if (mAlsoUseMoreRestrictiveLocales && length < 3) {
request.append(" or (locale like ?)");
// The following creates an array with one more (null) position
final String[] localeElementsWithMoreRestrictiveLocalesIncluded = Arrays.copyOf(localeElements, length + 1);
localeElementsWithMoreRestrictiveLocalesIncluded[length] = localeElements[length - 1] + "_%";
requestArguments = localeElementsWithMoreRestrictiveLocalesIncluded;
// If for example localeElements = ["en"]
// then requestArguments = ["en", "en_%"]
// and request = (locale is NULL) or (locale=?) or (locale like ?)
// If localeElements = ["en", "en_US"]
// then requestArguments = ["en", "en_US", "en_US_%"]
} else {
requestArguments = localeElements;
}
final String requestString = request.toString();
try {
addWordsFromProjectionLocked(PROJECTION_QUERY_WITH_SHORTCUT, requestString, requestArguments);
} catch (IllegalArgumentException e) {
// This may happen on some non-compliant devices where the declared API is JB+ but
// the SHORTCUT column is not present for some reason.
addWordsFromProjectionLocked(PROJECTION_QUERY_WITHOUT_SHORTCUT, requestString, requestArguments);
}
}
private void addWordsFromProjectionLocked(final String[] query, String request, final String[] requestArguments) throws IllegalArgumentException {
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(Words.CONTENT_URI, query, request, requestArguments, null);
addWordsLocked(cursor);
} catch (final SQLiteException e) {
Log.e(TAG, "SQLiteException in the remote User dictionary process.", e);
} finally {
try {
if (null != cursor)
cursor.close();
} catch (final SQLiteException e) {
Log.e(TAG, "SQLiteException in the remote User dictionary process.", e);
}
}
}
private static int scaleFrequencyFromDefaultToLatinIme(final int defaultFrequency) {
// The default frequency for the user dictionary is 250 for historical reasons.
// Latin IME considers a good value for the default user dictionary frequency
// is about 160 considering the scale we use. So we are scaling down the values.
if (defaultFrequency > Integer.MAX_VALUE / LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY) {
return (defaultFrequency / HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY) * LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY;
}
return (defaultFrequency * LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY) / HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY;
}
private void addWordsLocked(final Cursor cursor) {
final boolean hreplacedhortcutColumn = true;
if (cursor == null)
return;
if (cursor.moveToFirst()) {
final int indexWord = cursor.getColumnIndex(Words.WORD);
final int indexShortcut = hreplacedhortcutColumn ? cursor.getColumnIndex(Words.SHORTCUT) : 0;
final int indexFrequency = cursor.getColumnIndex(Words.FREQUENCY);
while (!cursor.isAfterLast()) {
final String word = cursor.getString(indexWord);
final String shortcut = hreplacedhortcutColumn ? cursor.getString(indexShortcut) : null;
final int frequency = cursor.getInt(indexFrequency);
final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency);
// Safeguard against adding really long words.
if (word.length() <= MAX_WORD_LENGTH) {
runGCIfRequiredLocked(true);
addUnigramLocked(word, adjustedFrequency, null, /* shortcutTarget */
0, /* shortcutFreq */
false, /* isNotAWord */
false, /* isPossiblyOffensive */
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
if (null != shortcut && shortcut.length() <= MAX_WORD_LENGTH) {
runGCIfRequiredLocked(true);
addUnigramLocked(shortcut, adjustedFrequency, word, USER_DICT_SHORTCUT_FREQUENCY, true, /* isNotAWord */
false, /* isPossiblyOffensive */
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
}
}
cursor.moveToNext();
}
}
}
}
18
Source : PhotoSetLoader.java
with Apache License 2.0
from yuchuangu85
with Apache License 2.0
from yuchuangu85
public clreplaced PhotoSetLoader extends CursorLoader implements LoaderCompatShim<Cursor> {
public static final String SUPPORTED_OPERATIONS = "supported_operations";
private static final Uri CONTENT_URI = Files.getContentUri("external");
public static final String[] PROJECTION = new String[] { FileColumns._ID, FileColumns.DATA, FileColumns.WIDTH, FileColumns.HEIGHT, FileColumns.DATE_ADDED, FileColumns.MEDIA_TYPE, SUPPORTED_OPERATIONS };
private static final String SORT_ORDER = FileColumns.DATE_ADDED + " DESC";
private static final String SELECTION = FileColumns.MEDIA_TYPE + " == " + FileColumns.MEDIA_TYPE_IMAGE + " OR " + FileColumns.MEDIA_TYPE + " == " + FileColumns.MEDIA_TYPE_VIDEO;
public static final int INDEX_ID = 0;
public static final int INDEX_DATA = 1;
public static final int INDEX_WIDTH = 2;
public static final int INDEX_HEIGHT = 3;
public static final int INDEX_DATE_ADDED = 4;
public static final int INDEX_MEDIA_TYPE = 5;
public static final int INDEX_SUPPORTED_OPERATIONS = 6;
private static final Uri GLOBAL_CONTENT_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/external/");
private final ContentObserver mGlobalObserver = new ForceLoadContentObserver();
public PhotoSetLoader(Context context) {
super(context, CONTENT_URI, PROJECTION, SELECTION, null, SORT_ORDER);
}
@Override
protected void onStartLoading() {
super.onStartLoading();
getContext().getContentResolver().registerContentObserver(GLOBAL_CONTENT_URI, true, mGlobalObserver);
}
@Override
protected void onReset() {
super.onReset();
getContext().getContentResolver().unregisterContentObserver(mGlobalObserver);
}
@Override
public Drawable drawableForItem(Cursor item, Drawable recycle) {
DataUriThumbnailDrawable drawable = null;
if (recycle == null || !(recycle instanceof DataUriThumbnailDrawable)) {
drawable = new DataUriThumbnailDrawable();
} else {
drawable = (DataUriThumbnailDrawable) recycle;
}
drawable.setImage(item.getString(INDEX_DATA), item.getInt(INDEX_WIDTH), item.getInt(INDEX_HEIGHT));
return drawable;
}
@Override
public Uri uriForItem(Cursor item) {
return null;
}
@Override
public ArrayList<Uri> urisForSubItems(Cursor item) {
return null;
}
@Override
public void deleteItemWithPath(Object path) {
}
@Override
public Object getPathForItem(Cursor item) {
return null;
}
}
18
Source : FavLoader.java
with GNU General Public License v3.0
from treasure-lau
with GNU General Public License v3.0
from treasure-lau
public clreplaced FavLoader extends AsyncTaskLoader<Cursor> {
private Cursor currentResult;
public FavLoader(Context context) {
super(context);
}
private ContentObserver loaderObserver = new ForceLoadContentObserver();
@Override
public Cursor loadInBackground() {
// First of all, get all active accounts
ArrayList<SipProfile> accounts = SipProfile.getAllProfiles(getContext(), true, new String[] { SipProfile.FIELD_ID, SipProfile.FIELD_ACC_ID, SipProfile.FIELD_ACTIVE, SipProfile.FIELD_DISPLAY_NAME, SipProfile.FIELD_WIZARD, SipProfile.FIELD_PRIORITY, SipProfile.FIELD_ANDROID_GROUP, SipProfile.FIELD_PUBLISH_ENABLED, SipProfile.FIELD_REG_URI, SipProfile.FIELD_PROXY });
Cursor[] cursorsToMerge = new Cursor[2 * accounts.size()];
int i = 0;
for (SipProfile acc : accounts) {
cursorsToMerge[i++] = createHeaderCursorFor(acc);
cursorsToMerge[i++] = createContentCursorFor(acc);
}
getContext().getContentResolver().registerContentObserver(SipProfile.ACCOUNT_STATUS_URI, true, loaderObserver);
if (cursorsToMerge.length > 0) {
MergeCursor mg = new MergeCursor(cursorsToMerge);
mg.registerContentObserver(loaderObserver);
return mg;
} else {
return null;
}
}
/**
* Called when there is new data to deliver to the client. The super clreplaced
* will take care of delivering it; the implementation here just adds a
* little more logic.
*/
@Override
public void deliverResult(Cursor c) {
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (currentResult != null) {
onReleaseResources(currentResult);
}
}
currentResult = c;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(c);
}
}
/**
* Handles a request to start the Loader.
*/
@Override
protected void onStartLoading() {
if (currentResult != null && !takeContentChanged()) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(currentResult);
} else {
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to cancel a load.
*/
@Override
public void onCanceled(Cursor c) {
super.onCanceled(c);
// At this point we can release the resources replacedociated with 'apps'
// if needed.
onReleaseResources(c);
}
/**
* Handles a request to completely reset the Loader.
*/
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources replacedociated with 'apps'
// if needed.
if (currentResult != null) {
onReleaseResources(currentResult);
currentResult = null;
}
}
/**
* Helper function to take care of releasing resources replacedociated with an
* actively loaded data set.
*/
protected void onReleaseResources(Cursor c) {
if (c != null) {
c.unregisterContentObserver(loaderObserver);
c.close();
}
getContext().getContentResolver().unregisterContentObserver(loaderObserver);
}
/**
* Creates a cursor that contains a single row and maps the section to the
* given value.
*/
private Cursor createHeaderCursorFor(SipProfile account) {
MatrixCursor matrixCursor = new MatrixCursor(new String[] { BaseColumns._ID, ContactsWrapper.FIELD_TYPE, SipProfile.FIELD_DISPLAY_NAME, SipProfile.FIELD_WIZARD, SipProfile.FIELD_ANDROID_GROUP, SipProfile.FIELD_PUBLISH_ENABLED, SipProfile.FIELD_REG_URI, SipProfile.FIELD_PROXY, SipProfile.FIELD_ACC_ID });
String proxies = "";
if (account.proxies != null) {
proxies = TextUtils.join(SipProfile.PROXIES_SEPARATOR, account.proxies);
}
matrixCursor.addRow(new Object[] { account.id, ContactsWrapper.TYPE_GROUP, account.display_name, account.wizard, account.android_group, account.publish_enabled, account.reg_uri, proxies, account.acc_id });
return matrixCursor;
}
/**
* Creates a cursor that contains contacts group corresponding to an sip
* account.
*/
private Cursor createContentCursorFor(SipProfile account) {
Cursor c = null;
if (!TextUtils.isEmpty(account.android_group)) {
c = ContactsWrapper.getInstance().getContactsByGroup(getContext(), account.android_group);
}
if (c != null) {
return c;
}
MatrixCursor mc = new MatrixCursor(new String[] { BaseColumns._ID, ContactsWrapper.FIELD_TYPE });
mc.addRow(new Object[] { account.id, ContactsWrapper.TYPE_CONFIGURE });
return mc;
}
}
18
Source : AccountsLoader.java
with GNU General Public License v3.0
from treasure-lau
with GNU General Public License v3.0
from treasure-lau
public clreplaced AccountsLoader extends AsyncTaskLoader<Cursor> {
public static final String FIELD_FORCE_CALL = "force_call";
public static final String FIELD_NBR_TO_CALL = "nbr_to_call";
public static final String FIELD_STATUS_OUTGOING = "status_for_outgoing";
public static final String FIELD_STATUS_COLOR = "status_color";
private static final String THIS_FILE = "OutgoingAccountsLoader";
private Cursor currentResult;
private final String numberToCall;
private final boolean ignoreRewritting;
private final boolean loadStatus;
private final boolean onlyActive;
private final boolean loadCallHandlerPlugins;
/**
* Constructor for loader for outgoing call context. <br/>
* This one will care of rewriting number and keep track of accounts status.
* @param context Your app context
* @param number Phone number for outgoing call
* @param ignoreRewrittingRules Should we ignore rewriting rules.
*/
public AccountsLoader(Context context, String number, boolean ignoreRewrittingRules) {
super(context);
numberToCall = number;
ignoreRewritting = ignoreRewrittingRules;
loadStatus = true;
onlyActive = true;
loadCallHandlerPlugins = true;
initHandlers();
}
public AccountsLoader(Context context, boolean onlyActiveAccounts, boolean withCallHandlerPlugins) {
super(context);
numberToCall = "";
ignoreRewritting = true;
loadStatus = false;
onlyActive = onlyActiveAccounts;
loadCallHandlerPlugins = withCallHandlerPlugins;
initHandlers();
}
private void initHandlers() {
CallHandlerPlugin.initHandler();
loaderObserver = new ForceLoadContentObserver();
}
private ContentObserver loaderObserver;
private ArrayList<FilteredProfile> finalAccounts;
@Override
public Cursor loadInBackground() {
// First register for status updates
if (loadStatus) {
getContext().getContentResolver().registerContentObserver(SipProfile.ACCOUNT_STATUS_URI, true, loaderObserver);
}
ArrayList<FilteredProfile> prefinalAccounts = new ArrayList<FilteredProfile>();
// Get all sip profiles
ArrayList<SipProfile> accounts;
PreferencesProviderWrapper prefsWrapper = new PreferencesProviderWrapper(getContext());
if (onlyActive && !prefsWrapper.isValidConnectionForOutgoing()) {
accounts = new ArrayList<SipProfile>();
} else {
accounts = SipProfile.getAllProfiles(getContext(), onlyActive, new String[] { SipProfile.FIELD_ID, SipProfile.FIELD_ACC_ID, SipProfile.FIELD_ACTIVE, SipProfile.FIELD_DISPLAY_NAME, SipProfile.FIELD_WIZARD });
}
// And all external call handlers
Map<String, String> externalHandlers;
if (loadCallHandlerPlugins) {
externalHandlers = CallHandlerPlugin.getAvailableCallHandlers(getContext());
} else {
externalHandlers = new HashMap<String, String>();
}
if (TextUtils.isEmpty(numberToCall)) {
// In case of empty number to call, just add everything without any other question
for (SipProfile acc : accounts) {
prefinalAccounts.add(new FilteredProfile(acc, false));
}
for (Entry<String, String> extEnt : externalHandlers.entrySet()) {
prefinalAccounts.add(new FilteredProfile(extEnt.getKey(), false));
}
} else {
// If there is a number to call, add only those callable, and flag must call entries
// Note that we keep processing all call handlers voluntarily cause we may encounter a sip account that doesn't register
// But is in force call mode
for (SipProfile acc : accounts) {
if (Filter.isCallableNumber(getContext(), acc.id, numberToCall)) {
boolean forceCall = Filter.isMustCallNumber(getContext(), acc.id, numberToCall);
prefinalAccounts.add(new FilteredProfile(acc, forceCall));
}
}
for (Entry<String, String> extEnt : externalHandlers.entrySet()) {
long accId = CallHandlerPlugin.getAccountIdForCallHandler(getContext(), extEnt.getKey());
if (Filter.isCallableNumber(getContext(), accId, numberToCall)) {
boolean forceCall = Filter.isMustCallNumber(getContext(), accId, numberToCall);
prefinalAccounts.add(new FilteredProfile(extEnt.getKey(), forceCall));
if (forceCall) {
break;
}
}
}
}
// Build final cursor based on final filtered accounts
Cursor[] cursorsToMerge = new Cursor[prefinalAccounts.size()];
int i = 0;
for (FilteredProfile acc : prefinalAccounts) {
cursorsToMerge[i++] = createCursorForAccount(acc);
}
if (cursorsToMerge.length > 0) {
MergeCursor mg = new MergeCursor(cursorsToMerge);
mg.registerContentObserver(loaderObserver);
finalAccounts = prefinalAccounts;
return mg;
} else {
finalAccounts = prefinalAccounts;
return null;
}
}
/**
* Clreplaced to hold information about a possible call handler entry.
* This could be either a sip profile or a call handler plugin
*/
private clreplaced FilteredProfile {
/**
* Sip profile constructor.
* To use when input is a sip profile
* @param acc The corresponding sip profile
* @param forceCall The force call flag in current context.
*/
public FilteredProfile(SipProfile acc, boolean forceCall) {
account = acc;
isForceCall = forceCall;
AccountStatusDisplay displayState = AccountListUtils.getAccountDisplay(getContext(), acc.id);
statusColor = displayState.statusColor;
statusForOutgoing = displayState.availableForCalls;
callHandlerPlugin = null;
}
/**
* Call handler plugin constructor.
* To use when input is a call handler plugin.
* @param componentName The component name of the plugin
* @param forceCall The force call flag in current context.
*/
public FilteredProfile(String componentName, boolean forceCall) {
account = new SipProfile();
long accId = CallHandlerPlugin.getAccountIdForCallHandler(getContext(), componentName);
account.id = accId;
account.wizard = "EXPERT";
CallHandlerPlugin ch = new CallHandlerPlugin(getContext());
final Semapreplaced semapreplaced = new Semapreplaced(0);
String toCall = numberToCall;
if (!ignoreRewritting) {
toCall = Filter.rewritePhoneNumber(getContext(), accId, numberToCall);
}
ch.loadFrom(accId, toCall, new OnLoadListener() {
@Override
public void onLoad(CallHandlerPlugin ch) {
Log.d(THIS_FILE, "Callhandler loaded");
semapreplaced.release();
}
});
boolean succeedInLoading = false;
try {
succeedInLoading = semapreplaced.tryAcquire(3L, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Log.e(THIS_FILE, "Not possible to bind callhandler plugin");
}
if (!succeedInLoading) {
Log.e(THIS_FILE, "Unreachable callhandler plugin " + componentName);
}
account.display_name = ch.getLabel();
account.icon = ch.getIcon();
isForceCall = forceCall;
statusColor = getContext().getResources().getColor(android.R.color.white);
statusForOutgoing = true;
callHandlerPlugin = ch;
}
final SipProfile account;
final boolean isForceCall;
final private boolean statusForOutgoing;
final private int statusColor;
final CallHandlerPlugin callHandlerPlugin;
/**
* Rewrite a number for this calling entry
* @param number The number to rewrite
* @return Rewritten number.
*/
public String rewriteNumber(String number) {
if (ignoreRewritting) {
return number;
} else {
return Filter.rewritePhoneNumber(getContext(), account.id, number);
}
}
/**
* Is the account available for outgoing calls
* @return True if a call can be made using this calling entry
*/
public boolean getStatusForOutgoing() {
return statusForOutgoing;
}
/**
* The color representing the calling entry status. green for registered
* sip accounts, red for invalid sip accounts, orange for sip accounts
* with ongoing registration, white for call handler plugins
*
* @return the color for this entry status.
*/
public int getStatusColor() {
return statusColor;
}
/**
* Get the eventual replacedociated call handler plugin object.
*
* @return The call handler plugin object if any replacedociated to this
* calling entry. Null if representing a sip account.
*/
public CallHandlerPlugin getCallHandlerPlugin() {
return callHandlerPlugin;
}
}
/**
* Called when there is new data to deliver to the client. The super clreplaced
* will take care of delivering it; the implementation here just adds a
* little more logic.
*/
@Override
public void deliverResult(Cursor c) {
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (currentResult != null) {
onReleaseResources(currentResult);
}
}
currentResult = c;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(c);
}
}
/**
* Handles a request to start the Loader.
*/
@Override
protected void onStartLoading() {
if (currentResult != null && !takeContentChanged()) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(currentResult);
} else {
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to cancel a load.
*/
@Override
public void onCanceled(Cursor c) {
super.onCanceled(c);
// At this point we can release the resources replacedociated with 'apps'
// if needed.
onReleaseResources(c);
}
/**
* Handles a request to completely reset the Loader.
*/
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources replacedociated with 'apps'
// if needed.
if (currentResult != null) {
onReleaseResources(currentResult);
currentResult = null;
}
}
/**
* Helper function to take care of releasing resources replacedociated with an
* actively loaded data set.
*/
protected void onReleaseResources(Cursor c) {
if (c != null) {
c.unregisterContentObserver(loaderObserver);
c.close();
}
if (loadStatus) {
getContext().getContentResolver().unregisterContentObserver(loaderObserver);
}
}
private static String[] COLUMN_HEADERS = new String[] { BaseColumns._ID, SipProfile.FIELD_ID, SipProfile.FIELD_DISPLAY_NAME, SipProfile.FIELD_WIZARD, FIELD_FORCE_CALL, FIELD_NBR_TO_CALL, FIELD_STATUS_OUTGOING, FIELD_STATUS_COLOR };
/**
* Creates a cursor that contains a single row and maps the section to the
* given value.
*/
private Cursor createCursorForAccount(FilteredProfile fa) {
MatrixCursor matrixCursor = new MatrixCursor(COLUMN_HEADERS);
matrixCursor.addRow(new Object[] { fa.account.id, fa.account.id, fa.account.display_name, fa.account.wizard, fa.isForceCall ? 1 : 0, fa.rewriteNumber(numberToCall), fa.getStatusForOutgoing() ? 1 : 0, fa.getStatusColor() });
return matrixCursor;
}
/**
* Get the cached call handler plugin loaded for a given position
* @param position The position to search at
* @return The call handler plugin if any for this position
*/
public CallHandlerPlugin getCallHandlerWithAccountId(long accId) {
for (FilteredProfile filteredAcc : finalAccounts) {
if (filteredAcc.account.id == accId)
return filteredAcc.getCallHandlerPlugin();
}
return null;
}
}
18
Source : AndroidWordLevelSpellCheckerSession.java
with Apache License 2.0
from sergchil
with Apache License 2.0
from sergchil
public abstract clreplaced AndroidWordLevelSpellCheckerSession extends Session {
private static final String TAG = AndroidWordLevelSpellCheckerSession.clreplaced.getSimpleName();
public final static String[] EMPTY_STRING_ARRAY = new String[0];
// Immutable, but not available in the constructor.
private Locale mLocale;
// Cache this for performance
// One of SCRIPT_LATIN or SCRIPT_CYRILLIC for now.
private int mScript;
private final AndroidSpellCheckerService mService;
protected final SuggestionsCache mSuggestionsCache = new SuggestionsCache();
private final ContentObserver mObserver;
private static final String quotesRegexp = "(\\u0022|\\u0027|\\u0060|\\u00B4|\\u2018|\\u2018|\\u201C|\\u201D)";
private static final clreplaced SuggestionsParams {
public final String[] mSuggestions;
public final int mFlags;
public SuggestionsParams(String[] suggestions, int flags) {
mSuggestions = suggestions;
mFlags = flags;
}
}
protected static final clreplaced SuggestionsCache {
private static final int MAX_CACHE_SIZE = 50;
private final LruCache<String, SuggestionsParams> mUnigramSuggestionsInfoCache = new LruCache<>(MAX_CACHE_SIZE);
private static String generateKey(final String query) {
return query + "";
}
public SuggestionsParams getSuggestionsFromCache(final String query) {
return mUnigramSuggestionsInfoCache.get(query);
}
public void putSuggestionsToCache(final String query, final String[] suggestions, final int flags) {
if (suggestions == null || TextUtils.isEmpty(query)) {
return;
}
mUnigramSuggestionsInfoCache.put(generateKey(query), new SuggestionsParams(suggestions, flags));
}
public void clearCache() {
mUnigramSuggestionsInfoCache.evictAll();
}
}
AndroidWordLevelSpellCheckerSession(final AndroidSpellCheckerService service) {
mService = service;
final ContentResolver cres = service.getContentResolver();
mObserver = new ContentObserver(null) {
@Override
public void onChange(boolean self) {
mSuggestionsCache.clearCache();
}
};
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver);
}
@Override
public void onCreate() {
final String localeString = getLocale();
mLocale = (null == localeString) ? null : LocaleUtils.constructLocaleFromString(localeString);
mScript = ScriptUtils.getScriptFromSpellCheckerLocale(mLocale);
}
@Override
public void onClose() {
final ContentResolver cres = mService.getContentResolver();
cres.unregisterContentObserver(mObserver);
}
private static final int CHECKABILITY_CHECKABLE = 0;
private static final int CHECKABILITY_TOO_MANY_NON_LETTERS = 1;
private static final int CHECKABILITY_CONTAINS_PERIOD = 2;
private static final int CHECKABILITY_EMAIL_OR_URL = 3;
private static final int CHECKABILITY_FIRST_LETTER_UNCHECKABLE = 4;
private static final int CHECKABILITY_TOO_SHORT = 5;
/**
* Finds out whether a particular string should be filtered out of spell checking.
*
* This will loosely match URLs, numbers, symbols. To avoid always underlining words that
* we know we will never recognize, this accepts a script identifier that should be one
* of the SCRIPT_* constants defined above, to rule out quickly characters from very
* different languages.
*
* @param text the string to evaluate.
* @param script the identifier for the script this spell checker recognizes
* @return one of the FILTER_OUT_* constants above.
*/
private static int getCheckabilityInScript(final String text, final int script) {
if (TextUtils.isEmpty(text) || text.length() <= 1)
return CHECKABILITY_TOO_SHORT;
// TODO: check if an equivalent processing can't be done more quickly with a
// compiled regexp.
// Filter by first letter
final int firstCodePoint = text.codePointAt(0);
// Filter out words that don't start with a letter or an apostrophe
if (!ScriptUtils.isLetterPartOfScript(firstCodePoint, script) && '\'' != firstCodePoint)
return CHECKABILITY_FIRST_LETTER_UNCHECKABLE;
// Filter contents
final int length = text.length();
int letterCount = 0;
for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) {
final int codePoint = text.codePointAt(i);
// Any word containing a COMMERCIAL_AT is probably an e-mail address
// Any word containing a SLASH is probably either an ad-hoc combination of two
// words or a URI - in either case we don't want to spell check that
if (Constants.CODE_COMMERCIAL_AT == codePoint || Constants.CODE_SLASH == codePoint) {
return CHECKABILITY_EMAIL_OR_URL;
}
// If the string contains a period, native returns strange suggestions (it seems
// to return suggestions for everything up to the period only and to ignore the
// rest), so we suppress lookup if there is a period.
// TODO: investigate why native returns these suggestions and remove this code.
if (Constants.CODE_PERIOD == codePoint) {
return CHECKABILITY_CONTAINS_PERIOD;
}
if (ScriptUtils.isLetterPartOfScript(codePoint, script))
++letterCount;
}
// Guestimate heuristic: perform spell checking if at least 3/4 of the characters
// in this word are letters
return (letterCount * 4 < length * 3) ? CHECKABILITY_TOO_MANY_NON_LETTERS : CHECKABILITY_CHECKABLE;
}
/**
* Helper method to test valid capitalizations of a word.
*
* If the "text" is lower-case, we test only the exact string.
* If the "Text" is capitalized, we test the exact string "Text" and the lower-cased
* version of it "text".
* If the "TEXT" is fully upper case, we test the exact string "TEXT", the lower-cased
* version of it "text" and the capitalized version of it "Text".
*/
private boolean isInDictForAnyCapitalization(final String text, final int capitalizeType) {
// If the word is in there as is, then it's in the dictionary. If not, we'll test lower
// case versions, but only if the word is not already all-lower case or mixed case.
if (mService.isValidWord(mLocale, text))
return true;
if (StringUtils.CAPITALIZE_NONE == capitalizeType)
return false;
// If we come here, we have a capitalized word (either First- or All-).
// Downcase the word and look it up again. If the word is only capitalized, we
// tested all possibilities, so if it's still negative we can return false.
final String lowerCaseText = text.toLowerCase(mLocale);
if (mService.isValidWord(mLocale, lowerCaseText))
return true;
if (StringUtils.CAPITALIZE_FIRST == capitalizeType)
return false;
// If the lower case version is not in the dictionary, it's still possible
// that we have an all-caps version of a word that needs to be capitalized
// according to the dictionary. E.g. "GERMANS" only exists in the dictionary as "Germans".
return mService.isValidWord(mLocale, StringUtils.capitalizeFirstAndDowncaseRest(lowerCaseText, mLocale));
}
// Note : this must be reentrant
/**
* Gets a list of suggestions for a specific string. This returns a list of possible
* corrections for the text preplaceded as an argument. It may split or group words, and
* even perform grammatical replacedysis.
*/
private SuggestionsInfo onGetSuggestionsInternal(final TextInfo textInfo, final int suggestionsLimit) {
return onGetSuggestionsInternal(textInfo, null, suggestionsLimit);
}
protected SuggestionsInfo onGetSuggestionsInternal(final TextInfo textInfo, final NgramContext ngramContext, final int suggestionsLimit) {
try {
final String text = textInfo.getText().replaceAll(AndroidSpellCheckerService.APOSTROPHE, AndroidSpellCheckerService.SINGLE_QUOTE).replaceAll("^" + quotesRegexp, "").replaceAll(quotesRegexp + "$", "");
if (!mService.hasMainDictionaryForLocale(mLocale)) {
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(false);
}
// Handle special patterns like email, URI, telephone number.
final int checkability = getCheckabilityInScript(text, mScript);
if (CHECKABILITY_CHECKABLE != checkability) {
if (CHECKABILITY_CONTAINS_PERIOD == checkability) {
final String[] splitText = text.split(Constants.REGEXP_PERIOD);
boolean allWordsAreValid = true;
for (final String word : splitText) {
if (!mService.isValidWord(mLocale, word)) {
allWordsAreValid = false;
break;
}
}
if (allWordsAreValid) {
return new SuggestionsInfo(SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO | SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS, new String[] { TextUtils.join(Constants.STRING_SPACE, splitText) });
}
}
return mService.isValidWord(mLocale, text) ? AndroidSpellCheckerService.getInDictEmptySuggestions() : AndroidSpellCheckerService.getNotInDictEmptySuggestions(CHECKABILITY_CONTAINS_PERIOD == checkability);
}
// Handle normal words.
final int capitalizeType = StringUtils.getCapitalizationType(text);
if (isInDictForAnyCapitalization(text, capitalizeType)) {
if (DebugFlags.DEBUG_ENABLED) {
Log.i(TAG, "onGetSuggestionsInternal() : [" + text + "] is a valid word");
}
return AndroidSpellCheckerService.getInDictEmptySuggestions();
}
if (DebugFlags.DEBUG_ENABLED) {
Log.i(TAG, "onGetSuggestionsInternal() : [" + text + "] is NOT a valid word");
}
final Keyboard keyboard = mService.getKeyboardForLocale(mLocale);
if (null == keyboard) {
Log.w(TAG, "onGetSuggestionsInternal() : No keyboard for locale: " + mLocale);
// If there is no keyboard for this locale, don't do any spell-checking.
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(false);
}
final WordComposer composer = new WordComposer();
final int[] codePoints = StringUtils.toCodePointArray(text);
final int[] coordinates;
coordinates = keyboard.getCoordinates(codePoints);
composer.setComposingWord(codePoints, coordinates);
// TODO: Don't gather suggestions if the limit is <= 0 unless necessary
final SuggestionResults suggestionResults = mService.getSuggestionResults(mLocale, composer.getComposedDataSnapshot(), ngramContext, keyboard);
final Result result = getResult(capitalizeType, mLocale, suggestionsLimit, mService.getRecommendedThreshold(), text, suggestionResults);
if (DebugFlags.DEBUG_ENABLED) {
if (result.mSuggestions != null && result.mSuggestions.length > 0) {
final StringBuilder builder = new StringBuilder();
for (String suggestion : result.mSuggestions) {
builder.append(" [");
builder.append(suggestion);
builder.append("]");
}
Log.i(TAG, "onGetSuggestionsInternal() : Suggestions =" + builder);
}
}
// Handle word not in dictionary.
// This is called only once per unique word, so entering multiple
// instances of the same word does not result in more than one call
// to this method.
// Also, upon changing the orientation of the device, this is called
// again for every unique invalid word in the text box.
StatsUtils.onInvalidWordIdentification(text);
final int flags = SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO | (result.mHasRecommendedSuggestions ? SuggestionsInfoCompatUtils.getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS() : 0);
final SuggestionsInfo retval = new SuggestionsInfo(flags, result.mSuggestions);
mSuggestionsCache.putSuggestionsToCache(text, result.mSuggestions, flags);
return retval;
} catch (RuntimeException e) {
// Don't kill the keyboard if there is a bug in the spell checker
Log.e(TAG, "Exception while spellchecking", e);
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(false);
}
}
private static final clreplaced Result {
public final String[] mSuggestions;
public final boolean mHasRecommendedSuggestions;
public Result(final String[] gatheredSuggestions, final boolean hasRecommendedSuggestions) {
mSuggestions = gatheredSuggestions;
mHasRecommendedSuggestions = hasRecommendedSuggestions;
}
}
private static Result getResult(final int capitalizeType, final Locale locale, final int suggestionsLimit, final float recommendedThreshold, final String originalText, final SuggestionResults suggestionResults) {
if (suggestionResults.isEmpty() || suggestionsLimit <= 0) {
return new Result(null, /* gatheredSuggestions */
false);
}
final ArrayList<String> suggestions = new ArrayList<>();
for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) {
final String suggestion;
if (StringUtils.CAPITALIZE_ALL == capitalizeType) {
suggestion = suggestedWordInfo.mWord.toUpperCase(locale);
} else if (StringUtils.CAPITALIZE_FIRST == capitalizeType) {
suggestion = StringUtils.capitalizeFirstCodePoint(suggestedWordInfo.mWord, locale);
} else {
suggestion = suggestedWordInfo.mWord;
}
suggestions.add(suggestion);
}
StringUtils.removeDupes(suggestions);
// This returns a String[], while toArray() returns an Object[] which cannot be cast
// into a String[].
final List<String> gatheredSuggestionsList = suggestions.subList(0, Math.min(suggestions.size(), suggestionsLimit));
final String[] gatheredSuggestions = gatheredSuggestionsList.toArray(new String[gatheredSuggestionsList.size()]);
final int bestScore = suggestionResults.first().mScore;
final String bestSuggestion = suggestions.get(0);
final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore(originalText, bestSuggestion, bestScore);
final boolean hasRecommendedSuggestions = (normalizedScore > recommendedThreshold);
return new Result(gatheredSuggestions, hasRecommendedSuggestions);
}
/*
* The spell checker acts on its own behalf. That is needed, in particular, to be able to
* access the dictionary files, which the provider restricts to the idenreplacedy of Latin IME.
* Since it's called externally by the application, the spell checker is using the idenreplacedy
* of the application by default unless we clearCallingIdenreplacedy.
* That's what the following method does.
*/
@Override
public SuggestionsInfo onGetSuggestions(final TextInfo textInfo, final int suggestionsLimit) {
long ident = Binder.clearCallingIdenreplacedy();
try {
return onGetSuggestionsInternal(textInfo, suggestionsLimit);
} finally {
Binder.restoreCallingIdenreplacedy(ident);
}
}
}
18
Source : ContentResolver.java
with Apache License 2.0
from oasisfeng
with Apache License 2.0
from oasisfeng
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
throw new RuntimeException("Stub!");
}
18
Source : ContentResolver.java
with Apache License 2.0
from oasisfeng
with Apache License 2.0
from oasisfeng
public void notifyChange(Uri uri, ContentObserver observer) {
throw new RuntimeException("Stub!");
}
18
Source : AndroidWordLevelSpellCheckerSession.java
with Apache License 2.0
from NlptechProduct
with Apache License 2.0
from NlptechProduct
public abstract clreplaced AndroidWordLevelSpellCheckerSession extends Session {
private static final String TAG = AndroidWordLevelSpellCheckerSession.clreplaced.getSimpleName();
public final static String[] EMPTY_STRING_ARRAY = new String[0];
// Immutable, but not available in the constructor.
private Locale mLocale;
// Cache this for performance
// One of SCRIPT_LATIN or SCRIPT_CYRILLIC for now.
private int mScript;
private final AndroidSpellCheckerService mService;
protected final SuggestionsCache mSuggestionsCache = new SuggestionsCache();
private final ContentObserver mObserver;
private static final String quotesRegexp = "(\\u0022|\\u0027|\\u0060|\\u00B4|\\u2018|\\u2018|\\u201C|\\u201D)";
private static final clreplaced SuggestionsParams {
public final String[] mSuggestions;
public final int mFlags;
public SuggestionsParams(String[] suggestions, int flags) {
mSuggestions = suggestions;
mFlags = flags;
}
}
protected static final clreplaced SuggestionsCache {
private static final int MAX_CACHE_SIZE = 50;
private final LruCache<String, SuggestionsParams> mUnigramSuggestionsInfoCache = new LruCache<>(MAX_CACHE_SIZE);
private static String generateKey(final String query) {
return query + "";
}
public SuggestionsParams getSuggestionsFromCache(final String query) {
return mUnigramSuggestionsInfoCache.get(query);
}
public void putSuggestionsToCache(final String query, final String[] suggestions, final int flags) {
if (suggestions == null || TextUtils.isEmpty(query)) {
return;
}
mUnigramSuggestionsInfoCache.put(generateKey(query), new SuggestionsParams(suggestions, flags));
}
public void clearCache() {
mUnigramSuggestionsInfoCache.evictAll();
}
}
AndroidWordLevelSpellCheckerSession(final AndroidSpellCheckerService service) {
mService = service;
final ContentResolver cres = service.getContentResolver();
mObserver = new ContentObserver(null) {
@Override
public void onChange(boolean self) {
mSuggestionsCache.clearCache();
}
};
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver);
}
@Override
public void onCreate() {
final String localeString = getLocale();
mLocale = (null == localeString) ? null : LocaleUtils.constructLocaleFromString(localeString);
mScript = ScriptUtils.getScriptFromSpellCheckerLocale(mLocale);
}
@Override
public void onClose() {
final ContentResolver cres = mService.getContentResolver();
cres.unregisterContentObserver(mObserver);
}
private static final int CHECKABILITY_CHECKABLE = 0;
private static final int CHECKABILITY_TOO_MANY_NON_LETTERS = 1;
private static final int CHECKABILITY_CONTAINS_PERIOD = 2;
private static final int CHECKABILITY_EMAIL_OR_URL = 3;
private static final int CHECKABILITY_FIRST_LETTER_UNCHECKABLE = 4;
private static final int CHECKABILITY_TOO_SHORT = 5;
/**
* Finds out whether a particular string should be filtered out of spell checking.
*
* This will loosely match URLs, numbers, symbols. To avoid always underlining words that
* we know we will never recognize, this accepts a script identifier that should be one
* of the SCRIPT_* constants defined above, to rule out quickly characters from very
* different languages.
*
* @param text the string to evaluate.
* @param script the identifier for the script this spell checker recognizes
* @return one of the FILTER_OUT_* constants above.
*/
private static int getCheckabilityInScript(final String text, final int script) {
if (TextUtils.isEmpty(text) || text.length() <= 1)
return CHECKABILITY_TOO_SHORT;
// TODO: check if an equivalent processing can't be done more quickly with a
// compiled regexp.
// Filter by first letter
final int firstCodePoint = text.codePointAt(0);
// Filter out words that don't start with a letter or an apostrophe
if (!ScriptUtils.isLetterPartOfScript(firstCodePoint, script) && '\'' != firstCodePoint)
return CHECKABILITY_FIRST_LETTER_UNCHECKABLE;
// Filter contents
final int length = text.length();
int letterCount = 0;
for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) {
final int codePoint = text.codePointAt(i);
// Any word containing a COMMERCIAL_AT is probably an e-mail address
// Any word containing a SLASH is probably either an ad-hoc combination of two
// words or a URI - in either case we don't want to spell check that
if (Constants.CODE_COMMERCIAL_AT == codePoint || Constants.CODE_SLASH == codePoint) {
return CHECKABILITY_EMAIL_OR_URL;
}
// If the string contains a period, native returns strange suggestions (it seems
// to return suggestions for everything up to the period only and to ignore the
// rest), so we suppress lookup if there is a period.
// TODO: investigate why native returns these suggestions and remove this code.
if (Constants.CODE_PERIOD == codePoint) {
return CHECKABILITY_CONTAINS_PERIOD;
}
if (ScriptUtils.isLetterPartOfScript(codePoint, script))
++letterCount;
}
// Guestimate heuristic: perform spell checking if at least 3/4 of the characters
// in this word are letters
return (letterCount * 4 < length * 3) ? CHECKABILITY_TOO_MANY_NON_LETTERS : CHECKABILITY_CHECKABLE;
}
/**
* Helper method to test valid capitalizations of a word.
*
* If the "text" is lower-case, we test only the exact string.
* If the "Text" is capitalized, we test the exact string "Text" and the lower-cased
* version of it "text".
* If the "TEXT" is fully upper case, we test the exact string "TEXT", the lower-cased
* version of it "text" and the capitalized version of it "Text".
*/
private boolean isInDictForAnyCapitalization(final String text, final int capitalizeType) {
// If the word is in there as is, then it's in the dictionary. If not, we'll test lower
// case versions, but only if the word is not already all-lower case or mixed case.
if (mService.isValidWord(mLocale, text))
return true;
if (StringUtils.CAPITALIZE_NONE == capitalizeType)
return false;
// If we come here, we have a capitalized word (either First- or All-).
// Downcase the word and look it up again. If the word is only capitalized, we
// tested all possibilities, so if it's still negative we can return false.
final String lowerCaseText = text.toLowerCase(mLocale);
if (mService.isValidWord(mLocale, lowerCaseText))
return true;
if (StringUtils.CAPITALIZE_FIRST == capitalizeType)
return false;
// If the lower case version is not in the dictionary, it's still possible
// that we have an all-caps version of a word that needs to be capitalized
// according to the dictionary. E.g. "GERMANS" only exists in the dictionary as "Germans".
return mService.isValidWord(mLocale, StringUtils.capitalizeFirstAndDowncaseRest(lowerCaseText, mLocale));
}
// Note : this must be reentrant
/**
* Gets a list of suggestions for a specific string. This returns a list of possible
* corrections for the text preplaceded as an argument. It may split or group words, and
* even perform grammatical replacedysis.
*/
private SuggestionsInfo onGetSuggestionsInternal(final TextInfo textInfo, final int suggestionsLimit) {
return onGetSuggestionsInternal(textInfo, null, suggestionsLimit);
}
protected SuggestionsInfo onGetSuggestionsInternal(final TextInfo textInfo, final NgramContext ngramContext, final int suggestionsLimit) {
try {
final String text = textInfo.getText().replaceAll(AndroidSpellCheckerService.APOSTROPHE, AndroidSpellCheckerService.SINGLE_QUOTE).replaceAll("^" + quotesRegexp, "").replaceAll(quotesRegexp + "$", "");
if (!mService.hasMainDictionaryForLocale(mLocale)) {
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(false);
}
// Handle special patterns like email, URI, telephone number.
final int checkability = getCheckabilityInScript(text, mScript);
if (CHECKABILITY_CHECKABLE != checkability) {
if (CHECKABILITY_CONTAINS_PERIOD == checkability) {
final String[] splitText = text.split(Constants.REGEXP_PERIOD);
boolean allWordsAreValid = true;
for (final String word : splitText) {
if (!mService.isValidWord(mLocale, word)) {
allWordsAreValid = false;
break;
}
}
if (allWordsAreValid) {
return new SuggestionsInfo(SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO | SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS, new String[] { TextUtils.join(Constants.STRING_SPACE, splitText) });
}
}
return mService.isValidWord(mLocale, text) ? AndroidSpellCheckerService.getInDictEmptySuggestions() : AndroidSpellCheckerService.getNotInDictEmptySuggestions(CHECKABILITY_CONTAINS_PERIOD == checkability);
}
// Handle normal words.
final int capitalizeType = StringUtils.getCapitalizationType(text);
if (isInDictForAnyCapitalization(text, capitalizeType)) {
if (DebugFlags.DEBUG_ENABLED) {
Log.i(TAG, "onGetSuggestionsInternal() : [" + text + "] is a valid word");
}
return AndroidSpellCheckerService.getInDictEmptySuggestions();
}
if (DebugFlags.DEBUG_ENABLED) {
Log.i(TAG, "onGetSuggestionsInternal() : [" + text + "] is NOT a valid word");
}
final Keyboard keyboard = mService.getKeyboardForLocale(mLocale);
if (null == keyboard) {
Log.w(TAG, "onGetSuggestionsInternal() : No keyboard for locale: " + mLocale);
// If there is no keyboard for this locale, don't do any spell-checking.
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(false);
}
final WordComposer composer = new WordComposer();
final int[] codePoints = StringUtils.toCodePointArray(text);
final int[] coordinates;
coordinates = keyboard.getCoordinates(codePoints);
composer.setComposingWord(codePoints, coordinates);
// TODO: Don't gather suggestions if the limit is <= 0 unless necessary
final SuggestionResults suggestionResults = mService.getSuggestionResults(mLocale, composer.getComposedDataSnapshot(), ngramContext, keyboard);
final Result result = getResult(capitalizeType, mLocale, suggestionsLimit, mService.getRecommendedThreshold(), text, suggestionResults);
if (DebugFlags.DEBUG_ENABLED) {
if (result.mSuggestions != null && result.mSuggestions.length > 0) {
final StringBuilder builder = new StringBuilder();
for (String suggestion : result.mSuggestions) {
builder.append(" [");
builder.append(suggestion);
builder.append("]");
}
Log.i(TAG, "onGetSuggestionsInternal() : Suggestions =" + builder);
}
}
// Handle word not in dictionary.
// This is called only once per unique word, so entering multiple
// instances of the same word does not result in more than one call
// to this method.
// Also, upon changing the orientation of the device, this is called
// again for every unique invalid word in the text box.
StatsUtils.onInvalidWordIdentification(text);
final int flags = SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO | (result.mHasRecommendedSuggestions ? SuggestionsInfoCompatUtils.getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS() : 0);
final SuggestionsInfo retval = new SuggestionsInfo(flags, result.mSuggestions);
mSuggestionsCache.putSuggestionsToCache(text, result.mSuggestions, flags);
return retval;
} catch (RuntimeException e) {
// Don't kill the keyboard if there is a bug in the spell checker
Log.e(TAG, "Exception while spellchecking", e);
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(false);
}
}
private static final clreplaced Result {
public final String[] mSuggestions;
public final boolean mHasRecommendedSuggestions;
public Result(final String[] gatheredSuggestions, final boolean hasRecommendedSuggestions) {
mSuggestions = gatheredSuggestions;
mHasRecommendedSuggestions = hasRecommendedSuggestions;
}
}
private static Result getResult(final int capitalizeType, final Locale locale, final int suggestionsLimit, final float recommendedThreshold, final String originalText, final SuggestionResults suggestionResults) {
if (suggestionResults.isEmpty() || suggestionsLimit <= 0) {
return new Result(null, /* gatheredSuggestions */
false);
}
final ArrayList<String> suggestions = new ArrayList<>();
for (final SuggestedWords.SuggestedWordInfo suggestedWordInfo : suggestionResults) {
final String suggestion;
if (StringUtils.CAPITALIZE_ALL == capitalizeType) {
suggestion = suggestedWordInfo.mWord.toUpperCase(locale);
} else if (StringUtils.CAPITALIZE_FIRST == capitalizeType) {
suggestion = StringUtils.capitalizeFirstCodePoint(suggestedWordInfo.mWord, locale);
} else {
suggestion = suggestedWordInfo.mWord;
}
suggestions.add(suggestion);
}
StringUtils.removeDupes(suggestions);
// This returns a String[], while toArray() returns an Object[] which cannot be cast
// into a String[].
final List<String> gatheredSuggestionsList = suggestions.subList(0, Math.min(suggestions.size(), suggestionsLimit));
final String[] gatheredSuggestions = gatheredSuggestionsList.toArray(new String[gatheredSuggestionsList.size()]);
final int bestScore = suggestionResults.first().mScore;
final String bestSuggestion = suggestions.get(0);
final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore(originalText, bestSuggestion, bestScore);
final boolean hasRecommendedSuggestions = (normalizedScore > recommendedThreshold);
return new Result(gatheredSuggestions, hasRecommendedSuggestions);
}
/*
* The spell checker acts on its own behalf. That is needed, in particular, to be able to
* access the dictionary files, which the provider restricts to the idenreplacedy of Latin IME.
* Since it's called externally by the application, the spell checker is using the idenreplacedy
* of the application by default unless we clearCallingIdenreplacedy.
* That's what the following method does.
*/
@Override
public SuggestionsInfo onGetSuggestions(final TextInfo textInfo, final int suggestionsLimit) {
long ident = Binder.clearCallingIdenreplacedy();
try {
return onGetSuggestionsInternal(textInfo, suggestionsLimit);
} finally {
Binder.restoreCallingIdenreplacedy(ident);
}
}
}
18
Source : SettingsCursor.java
with GNU General Public License v3.0
from MuntashirAkon
with GNU General Public License v3.0
from MuntashirAkon
@Override
public void registerContentObserver(ContentObserver contentObserver) {
if (cursor != null)
cursor.registerContentObserver(contentObserver);
}
18
Source : GroupedThreadMediaLoader.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
public final clreplaced GroupedThreadMediaLoader extends AsyncTaskLoader<GroupedThreadMediaLoader.GroupedThreadMedia> {
@SuppressWarnings("unused")
private static final String TAG = Log.tag(GroupedThreadMediaLoader.clreplaced);
private final ContentObserver observer;
private final MediaLoader.MediaType mediaType;
private final MediaDatabase.Sorting sorting;
private final long threadId;
public GroupedThreadMediaLoader(@NonNull Context context, long threadId, @NonNull MediaLoader.MediaType mediaType, @NonNull MediaDatabase.Sorting sorting) {
super(context);
this.threadId = threadId;
this.mediaType = mediaType;
this.sorting = sorting;
this.observer = new ForceLoadContentObserver();
onContentChanged();
}
@Override
protected void onStartLoading() {
if (takeContentChanged()) {
forceLoad();
}
}
@Override
protected void onStopLoading() {
cancelLoad();
}
@Override
protected void onAbandon() {
DatabaseFactory.getMediaDatabase(getContext()).unsubscribeToMediaChanges(observer);
}
@Override
public GroupedThreadMedia loadInBackground() {
Context context = getContext();
GroupingMethod groupingMethod = sorting.isRelatedToFileSize() ? new RoughSizeGroupingMethod(context) : new DateGroupingMethod(context, CalendarDateOnly.getInstance());
PopulatedGroupedThreadMedia mediaGrouping = new PopulatedGroupedThreadMedia(groupingMethod);
DatabaseFactory.getMediaDatabase(context).subscribeToMediaChanges(observer);
try (Cursor cursor = ThreadMediaLoader.createThreadMediaCursor(context, threadId, mediaType, sorting)) {
while (cursor != null && cursor.moveToNext()) {
mediaGrouping.add(MediaDatabase.MediaRecord.from(context, cursor));
}
}
if (sorting == MediaDatabase.Sorting.Oldest || sorting == MediaDatabase.Sorting.Largest) {
return new ReversedGroupedThreadMedia(mediaGrouping);
} else {
return mediaGrouping;
}
}
public interface GroupingMethod {
int groupForRecord(@NonNull MediaDatabase.MediaRecord mediaRecord);
@NonNull
String groupName(int groupNo);
}
public static clreplaced DateGroupingMethod implements GroupingMethod {
private final Context context;
private final long yesterdayStart;
private final long todayStart;
private final long thisWeekStart;
private final long thisMonthStart;
private static final int TODAY = Integer.MIN_VALUE;
private static final int YESTERDAY = Integer.MIN_VALUE + 1;
private static final int THIS_WEEK = Integer.MIN_VALUE + 2;
private static final int THIS_MONTH = Integer.MIN_VALUE + 3;
DateGroupingMethod(@NonNull Context context, @NonNull Calendar today) {
this.context = context;
todayStart = today.getTimeInMillis();
yesterdayStart = getTimeInMillis(today, Calendar.DAY_OF_YEAR, -1);
thisWeekStart = getTimeInMillis(today, Calendar.DAY_OF_YEAR, -6);
thisMonthStart = getTimeInMillis(today, Calendar.DAY_OF_YEAR, -30);
}
private static long getTimeInMillis(@NonNull Calendar now, int field, int offset) {
Calendar copy = (Calendar) now.clone();
copy.add(field, offset);
return copy.getTimeInMillis();
}
@Override
public int groupForRecord(@NonNull MediaDatabase.MediaRecord mediaRecord) {
long date = mediaRecord.getDate();
if (date > todayStart)
return TODAY;
if (date > yesterdayStart)
return YESTERDAY;
if (date > thisWeekStart)
return THIS_WEEK;
if (date > thisMonthStart)
return THIS_MONTH;
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
return -(year * 12 + month);
}
@Override
@NonNull
public String groupName(int groupNo) {
switch(groupNo) {
case TODAY:
return context.getString(R.string.BucketedThreadMedia_Today);
case YESTERDAY:
return context.getString(R.string.BucketedThreadMedia_Yesterday);
case THIS_WEEK:
return context.getString(R.string.BucketedThreadMedia_This_week);
case THIS_MONTH:
return context.getString(R.string.BucketedThreadMedia_This_month);
default:
int yearAndMonth = -groupNo;
int month = yearAndMonth % 12;
int year = yearAndMonth / 12;
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
return new SimpleDateFormat("MMMM, yyyy", Locale.getDefault()).format(calendar.getTime());
}
}
}
public static clreplaced RoughSizeGroupingMethod implements GroupingMethod {
private final String largeDescription;
private final String mediumDescription;
private final String smallDescription;
private static final int MB = 1024 * 1024;
private static final int SMALL = 0;
private static final int MEDIUM = 1;
private static final int LARGE = 2;
RoughSizeGroupingMethod(@NonNull Context context) {
smallDescription = context.getString(R.string.BucketedThreadMedia_Small);
mediumDescription = context.getString(R.string.BucketedThreadMedia_Medium);
largeDescription = context.getString(R.string.BucketedThreadMedia_Large);
}
@Override
public int groupForRecord(@NonNull MediaDatabase.MediaRecord mediaRecord) {
long size = mediaRecord.getAttachment().getSize();
if (size < MB)
return SMALL;
if (size < 20 * MB)
return MEDIUM;
return LARGE;
}
@Override
@NonNull
public String groupName(int groupNo) {
switch(groupNo) {
case SMALL:
return smallDescription;
case MEDIUM:
return mediumDescription;
case LARGE:
return largeDescription;
default:
throw new replacedertionError();
}
}
}
public static abstract clreplaced GroupedThreadMedia {
public abstract int getSectionCount();
public abstract int getSectionItemCount(int section);
@NonNull
public abstract MediaDatabase.MediaRecord get(int section, int item);
@NonNull
public abstract String getName(int section);
}
public static clreplaced EmptyGroupedThreadMedia extends GroupedThreadMedia {
@Override
public int getSectionCount() {
return 0;
}
@Override
public int getSectionItemCount(int section) {
return 0;
}
@Override
@NonNull
public MediaDatabase.MediaRecord get(int section, int item) {
throw new replacedertionError();
}
@Override
@NonNull
public String getName(int section) {
throw new replacedertionError();
}
}
public static clreplaced ReversedGroupedThreadMedia extends GroupedThreadMedia {
private final GroupedThreadMedia decorated;
ReversedGroupedThreadMedia(@NonNull GroupedThreadMedia decorated) {
this.decorated = decorated;
}
@Override
public int getSectionCount() {
return decorated.getSectionCount();
}
@Override
public int getSectionItemCount(int section) {
return decorated.getSectionItemCount(getReversedSection(section));
}
@Override
@NonNull
public MediaDatabase.MediaRecord get(int section, int item) {
return decorated.get(getReversedSection(section), item);
}
@Override
@NonNull
public String getName(int section) {
return decorated.getName(getReversedSection(section));
}
private int getReversedSection(int section) {
return decorated.getSectionCount() - 1 - section;
}
}
private static clreplaced PopulatedGroupedThreadMedia extends GroupedThreadMedia {
@NonNull
private final GroupingMethod groupingMethod;
private final SparseArray<List<MediaDatabase.MediaRecord>> records = new SparseArray<>();
private PopulatedGroupedThreadMedia(@NonNull GroupingMethod groupingMethod) {
this.groupingMethod = groupingMethod;
}
private void add(@NonNull MediaDatabase.MediaRecord mediaRecord) {
int groupNo = groupingMethod.groupForRecord(mediaRecord);
List<MediaDatabase.MediaRecord> mediaRecords = records.get(groupNo);
if (mediaRecords == null) {
mediaRecords = new LinkedList<>();
records.put(groupNo, mediaRecords);
}
mediaRecords.add(mediaRecord);
}
@Override
public int getSectionCount() {
return records.size();
}
@Override
public int getSectionItemCount(int section) {
return records.get(records.keyAt(section)).size();
}
@Override
@NonNull
public MediaDatabase.MediaRecord get(int section, int item) {
return records.get(records.keyAt(section)).get(item);
}
@Override
@NonNull
public String getName(int section) {
return groupingMethod.groupName(records.keyAt(section));
}
}
}
18
Source : Database.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
protected void registerAttachmentListeners(@NonNull ContentObserver observer) {
context.getContentResolver().registerContentObserver(DatabaseContentProviders.Attachment.CONTENT_URI, true, observer);
}
18
Source : CalendarTracker.java
with Apache License 2.0
from lulululbj
with Apache License 2.0
from lulululbj
public clreplaced CalendarTracker {
private static final String TAG = "ConditionProviders.CT";
private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
private static final boolean DEBUG_ATTENDEES = false;
private static final int EVENT_CHECK_LOOKAHEAD = 24 * 60 * 60 * 1000;
private static final String[] INSTANCE_PROJECTION = { Instances.BEGIN, Instances.END, Instances.replacedLE, Instances.VISIBLE, Instances.EVENT_ID, Instances.CALENDAR_DISPLAY_NAME, Instances.OWNER_ACCOUNT, Instances.CALENDAR_ID, Instances.AVAILABILITY };
private static final String INSTANCE_ORDER_BY = Instances.BEGIN + " ASC";
private static final String[] ATTENDEE_PROJECTION = { Attendees.EVENT_ID, Attendees.ATTENDEE_EMAIL, Attendees.ATTENDEE_STATUS };
private static final String ATTENDEE_SELECTION = Attendees.EVENT_ID + " = ? AND " + Attendees.ATTENDEE_EMAIL + " = ?";
private final Context mSystemContext;
private final Context mUserContext;
private Callback mCallback;
private boolean mRegistered;
public CalendarTracker(Context systemContext, Context userContext) {
mSystemContext = systemContext;
mUserContext = userContext;
}
public void setCallback(Callback callback) {
if (mCallback == callback)
return;
mCallback = callback;
setRegistered(mCallback != null);
}
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("mCallback=");
pw.println(mCallback);
pw.print(prefix);
pw.print("mRegistered=");
pw.println(mRegistered);
pw.print(prefix);
pw.print("u=");
pw.println(mUserContext.getUserId());
}
private ArraySet<Long> getPrimaryCalendars() {
final long start = System.currentTimeMillis();
final ArraySet<Long> rt = new ArraySet<>();
final String primary = "\"primary\"";
final String[] projection = { Calendars._ID, "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + primary };
final String selection = primary + " = 1";
Cursor cursor = null;
try {
cursor = mUserContext.getContentResolver().query(Calendars.CONTENT_URI, projection, selection, null, null);
while (cursor != null && cursor.moveToNext()) {
rt.add(cursor.getLong(0));
}
} finally {
if (cursor != null) {
cursor.close();
}
}
if (DEBUG)
Log.d(TAG, "getPrimaryCalendars took " + (System.currentTimeMillis() - start));
return rt;
}
public CheckEventResult checkEvent(EventInfo filter, long time) {
final Uri.Builder uriBuilder = Instances.CONTENT_URI.buildUpon();
ContentUris.appendId(uriBuilder, time);
ContentUris.appendId(uriBuilder, time + EVENT_CHECK_LOOKAHEAD);
final Uri uri = uriBuilder.build();
final Cursor cursor = mUserContext.getContentResolver().query(uri, INSTANCE_PROJECTION, null, null, INSTANCE_ORDER_BY);
final CheckEventResult result = new CheckEventResult();
result.recheckAt = time + EVENT_CHECK_LOOKAHEAD;
try {
final ArraySet<Long> primaryCalendars = getPrimaryCalendars();
while (cursor != null && cursor.moveToNext()) {
final long begin = cursor.getLong(0);
final long end = cursor.getLong(1);
final String replacedle = cursor.getString(2);
final boolean calendarVisible = cursor.getInt(3) == 1;
final int eventId = cursor.getInt(4);
final String name = cursor.getString(5);
final String owner = cursor.getString(6);
final long calendarId = cursor.getLong(7);
final int availability = cursor.getInt(8);
final boolean calendarPrimary = primaryCalendars.contains(calendarId);
if (DEBUG)
Log.d(TAG, String.format("%s %s-%s v=%s a=%s eid=%s n=%s o=%s cid=%s p=%s", replacedle, new Date(begin), new Date(end), calendarVisible, availabilityToString(availability), eventId, name, owner, calendarId, calendarPrimary));
final boolean meetsTime = time >= begin && time < end;
final boolean meetsCalendar = calendarVisible && calendarPrimary && (filter.calendar == null || Objects.equals(filter.calendar, owner) || Objects.equals(filter.calendar, name));
final boolean meetsAvailability = availability != Instances.AVAILABILITY_FREE;
if (meetsCalendar && meetsAvailability) {
if (DEBUG)
Log.d(TAG, " MEETS CALENDAR & AVAILABILITY");
final boolean meetsAttendee = meetsAttendee(filter, eventId, owner);
if (meetsAttendee) {
if (DEBUG)
Log.d(TAG, " MEETS ATTENDEE");
if (meetsTime) {
if (DEBUG)
Log.d(TAG, " MEETS TIME");
result.inEvent = true;
}
if (begin > time && begin < result.recheckAt) {
result.recheckAt = begin;
} else if (end > time && end < result.recheckAt) {
result.recheckAt = end;
}
}
}
}
} catch (Exception e) {
Slog.w(TAG, "error reading calendar", e);
} finally {
if (cursor != null) {
cursor.close();
}
}
return result;
}
private boolean meetsAttendee(EventInfo filter, int eventId, String email) {
final long start = System.currentTimeMillis();
String selection = ATTENDEE_SELECTION;
String[] selectionArgs = { Integer.toString(eventId), email };
if (DEBUG_ATTENDEES) {
selection = null;
selectionArgs = null;
}
final Cursor cursor = mUserContext.getContentResolver().query(Attendees.CONTENT_URI, ATTENDEE_PROJECTION, selection, selectionArgs, null);
try {
if (cursor == null || cursor.getCount() == 0) {
if (DEBUG)
Log.d(TAG, "No attendees found");
return true;
}
boolean rt = false;
while (cursor != null && cursor.moveToNext()) {
final long rowEventId = cursor.getLong(0);
final String rowEmail = cursor.getString(1);
final int status = cursor.getInt(2);
final boolean meetsReply = meetsReply(filter.reply, status);
if (DEBUG)
Log.d(TAG, (DEBUG_ATTENDEES ? String.format("rowEventId=%s, rowEmail=%s, ", rowEventId, rowEmail) : "") + String.format("status=%s, meetsReply=%s", attendeeStatusToString(status), meetsReply));
final boolean eventMeets = rowEventId == eventId && Objects.equals(rowEmail, email) && meetsReply;
rt |= eventMeets;
}
return rt;
} finally {
if (cursor != null) {
cursor.close();
}
if (DEBUG)
Log.d(TAG, "meetsAttendee took " + (System.currentTimeMillis() - start));
}
}
private void setRegistered(boolean registered) {
if (mRegistered == registered)
return;
final ContentResolver cr = mSystemContext.getContentResolver();
final int userId = mUserContext.getUserId();
if (mRegistered) {
if (DEBUG)
Log.d(TAG, "unregister content observer u=" + userId);
cr.unregisterContentObserver(mObserver);
}
mRegistered = registered;
if (DEBUG)
Log.d(TAG, "mRegistered = " + registered + " u=" + userId);
if (mRegistered) {
if (DEBUG)
Log.d(TAG, "register content observer u=" + userId);
cr.registerContentObserver(Instances.CONTENT_URI, true, mObserver, userId);
cr.registerContentObserver(Events.CONTENT_URI, true, mObserver, userId);
cr.registerContentObserver(Calendars.CONTENT_URI, true, mObserver, userId);
}
}
private static String attendeeStatusToString(int status) {
switch(status) {
case Attendees.ATTENDEE_STATUS_NONE:
return "ATTENDEE_STATUS_NONE";
case Attendees.ATTENDEE_STATUS_ACCEPTED:
return "ATTENDEE_STATUS_ACCEPTED";
case Attendees.ATTENDEE_STATUS_DECLINED:
return "ATTENDEE_STATUS_DECLINED";
case Attendees.ATTENDEE_STATUS_INVITED:
return "ATTENDEE_STATUS_INVITED";
case Attendees.ATTENDEE_STATUS_TENTATIVE:
return "ATTENDEE_STATUS_TENTATIVE";
default:
return "ATTENDEE_STATUS_UNKNOWN_" + status;
}
}
private static String availabilityToString(int availability) {
switch(availability) {
case Instances.AVAILABILITY_BUSY:
return "AVAILABILITY_BUSY";
case Instances.AVAILABILITY_FREE:
return "AVAILABILITY_FREE";
case Instances.AVAILABILITY_TENTATIVE:
return "AVAILABILITY_TENTATIVE";
default:
return "AVAILABILITY_UNKNOWN_" + availability;
}
}
private static boolean meetsReply(int reply, int attendeeStatus) {
switch(reply) {
case EventInfo.REPLY_YES:
return attendeeStatus == Attendees.ATTENDEE_STATUS_ACCEPTED;
case EventInfo.REPLY_YES_OR_MAYBE:
return attendeeStatus == Attendees.ATTENDEE_STATUS_ACCEPTED || attendeeStatus == Attendees.ATTENDEE_STATUS_TENTATIVE;
case EventInfo.REPLY_ANY_EXCEPT_NO:
return attendeeStatus != Attendees.ATTENDEE_STATUS_DECLINED;
default:
return false;
}
}
private final ContentObserver mObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange, Uri u) {
if (DEBUG)
Log.d(TAG, "onChange selfChange=" + selfChange + " uri=" + u + " u=" + mUserContext.getUserId());
mCallback.onChanged();
}
@Override
public void onChange(boolean selfChange) {
if (DEBUG)
Log.d(TAG, "onChange selfChange=" + selfChange);
}
};
public static clreplaced CheckEventResult {
public boolean inEvent;
public long recheckAt;
}
public interface Callback {
void onChanged();
}
}
18
Source : ScreenShotHelper.java
with GNU General Public License v3.0
from farkam135
with GNU General Public License v3.0
from farkam135
public clreplaced ScreenShotHelper {
private static ScreenShotHelper instance = null;
public static boolean sShouldRecalibrateWithNextScreenshot = false;
private ContentObserver mediaObserver;
private ContentResolver contentResolver;
private String getRealPathFromUri(Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = contentResolver.query(contentUri, proj, null, null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
private ScreenShotHelper(final Context context) {
this.contentResolver = context.getContentResolver();
mediaObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
if (!uri.toString().contains("images")) {
return;
}
final String pathChange = getRealPathFromUri(uri);
if (!pathChange.contains("Screenshot")) {
return;
}
/* Ignore random events related to opening old screenshots by making
* sure the file was created within the past 10 seconds.
*/
long now = Calendar.getInstance().getTimeInMillis();
long filetime = new File(pathChange).lastModified();
if (now - filetime > 10000) {
return;
}
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeFile(pathChange);
} catch (Exception e) {
Timber.log(Log.ERROR, e);
} finally {
if (bitmap != null) {
if (sShouldRecalibrateWithNextScreenshot) {
// Use the screenshot to recalibrate GoIV
OcrCalibrationResultActivity.startCalibration(context, bitmap, 0, 0);
sShouldRecalibrateWithNextScreenshot = false;
if (GoIVSettings.getInstance(context).shouldDeleteScreenshots()) {
deleteScreenShot(pathChange);
}
} else {
// Scan 'mon info
Intent newintent = Pokefly.createProcessBitmapIntent(bitmap, pathChange);
LocalBroadcastManager.getInstance(context).sendBroadcast(newintent);
}
}
}
}
};
contentResolver.registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, mediaObserver);
}
public static ScreenShotHelper start(final Context context) {
if (instance == null) {
instance = new ScreenShotHelper(context);
}
return instance;
}
public void deleteScreenShot(String filePath) {
contentResolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Files.FileColumns.DATA + "=?", new String[] { filePath });
}
public void stop() {
contentResolver.unregisterContentObserver(mediaObserver);
contentResolver = null;
mediaObserver = null;
instance = null;
}
}
18
Source : AndroidWordLevelSpellCheckerSession.java
with GNU General Public License v3.0
from dslul
with GNU General Public License v3.0
from dslul
public abstract clreplaced AndroidWordLevelSpellCheckerSession extends Session {
private static final String TAG = AndroidWordLevelSpellCheckerSession.clreplaced.getSimpleName();
public final static String[] EMPTY_STRING_ARRAY = new String[0];
// Immutable, but not available in the constructor.
private Locale mLocale;
// Cache this for performance
// One of SCRIPT_LATIN or SCRIPT_CYRILLIC for now.
private int mScript;
private final AndroidSpellCheckerService mService;
protected final SuggestionsCache mSuggestionsCache = new SuggestionsCache();
private final ContentObserver mObserver;
private static final String quotesRegexp = "(\\u0022|\\u0027|\\u0060|\\u00B4|\\u2018|\\u2018|\\u201C|\\u201D)";
private static final clreplaced SuggestionsParams {
public final String[] mSuggestions;
public final int mFlags;
public SuggestionsParams(String[] suggestions, int flags) {
mSuggestions = suggestions;
mFlags = flags;
}
}
protected static final clreplaced SuggestionsCache {
private static final int MAX_CACHE_SIZE = 50;
private final LruCache<String, SuggestionsParams> mUnigramSuggestionsInfoCache = new LruCache<>(MAX_CACHE_SIZE);
private static String generateKey(final String query) {
return query + "";
}
public SuggestionsParams getSuggestionsFromCache(final String query) {
return mUnigramSuggestionsInfoCache.get(query);
}
public void putSuggestionsToCache(final String query, final String[] suggestions, final int flags) {
if (suggestions == null || TextUtils.isEmpty(query)) {
return;
}
mUnigramSuggestionsInfoCache.put(generateKey(query), new SuggestionsParams(suggestions, flags));
}
public void clearCache() {
mUnigramSuggestionsInfoCache.evictAll();
}
}
AndroidWordLevelSpellCheckerSession(final AndroidSpellCheckerService service) {
mService = service;
final ContentResolver cres = service.getContentResolver();
mObserver = new ContentObserver(null) {
@Override
public void onChange(boolean self) {
mSuggestionsCache.clearCache();
}
};
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver);
}
@Override
public void onCreate() {
final String localeString = getLocale();
mLocale = (null == localeString) ? null : LocaleUtils.constructLocaleFromString(localeString);
mScript = ScriptUtils.getScriptFromSpellCheckerLocale(mLocale);
}
@Override
public void onClose() {
final ContentResolver cres = mService.getContentResolver();
cres.unregisterContentObserver(mObserver);
}
private static final int CHECKABILITY_CHECKABLE = 0;
private static final int CHECKABILITY_TOO_MANY_NON_LETTERS = 1;
private static final int CHECKABILITY_CONTAINS_PERIOD = 2;
private static final int CHECKABILITY_EMAIL_OR_URL = 3;
private static final int CHECKABILITY_FIRST_LETTER_UNCHECKABLE = 4;
private static final int CHECKABILITY_TOO_SHORT = 5;
/**
* Finds out whether a particular string should be filtered out of spell checking.
*
* This will loosely match URLs, numbers, symbols. To avoid always underlining words that
* we know we will never recognize, this accepts a script identifier that should be one
* of the SCRIPT_* constants defined above, to rule out quickly characters from very
* different languages.
*
* @param text the string to evaluate.
* @param script the identifier for the script this spell checker recognizes
* @return one of the FILTER_OUT_* constants above.
*/
private static int getCheckabilityInScript(final String text, final int script) {
if (TextUtils.isEmpty(text) || text.length() <= 1)
return CHECKABILITY_TOO_SHORT;
// TODO: check if an equivalent processing can't be done more quickly with a
// compiled regexp.
// Filter by first letter
final int firstCodePoint = text.codePointAt(0);
// Filter out words that don't start with a letter or an apostrophe
if (!ScriptUtils.isLetterPartOfScript(firstCodePoint, script) && '\'' != firstCodePoint)
return CHECKABILITY_FIRST_LETTER_UNCHECKABLE;
// Filter contents
final int length = text.length();
int letterCount = 0;
for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) {
final int codePoint = text.codePointAt(i);
// Any word containing a COMMERCIAL_AT is probably an e-mail address
// Any word containing a SLASH is probably either an ad-hoc combination of two
// words or a URI - in either case we don't want to spell check that
if (Constants.CODE_COMMERCIAL_AT == codePoint || Constants.CODE_SLASH == codePoint) {
return CHECKABILITY_EMAIL_OR_URL;
}
// If the string contains a period, native returns strange suggestions (it seems
// to return suggestions for everything up to the period only and to ignore the
// rest), so we suppress lookup if there is a period.
// TODO: investigate why native returns these suggestions and remove this code.
if (Constants.CODE_PERIOD == codePoint) {
return CHECKABILITY_CONTAINS_PERIOD;
}
if (ScriptUtils.isLetterPartOfScript(codePoint, script))
++letterCount;
}
// Guestimate heuristic: perform spell checking if at least 3/4 of the characters
// in this word are letters
return (letterCount * 4 < length * 3) ? CHECKABILITY_TOO_MANY_NON_LETTERS : CHECKABILITY_CHECKABLE;
}
/**
* Helper method to test valid capitalizations of a word.
*
* If the "text" is lower-case, we test only the exact string.
* If the "Text" is capitalized, we test the exact string "Text" and the lower-cased
* version of it "text".
* If the "TEXT" is fully upper case, we test the exact string "TEXT", the lower-cased
* version of it "text" and the capitalized version of it "Text".
*/
private boolean isInDictForAnyCapitalization(final String text, final int capitalizeType) {
// If the word is in there as is, then it's in the dictionary. If not, we'll test lower
// case versions, but only if the word is not already all-lower case or mixed case.
if (mService.isValidWord(mLocale, text))
return true;
if (StringUtils.CAPITALIZE_NONE == capitalizeType)
return false;
// If we come here, we have a capitalized word (either First- or All-).
// Downcase the word and look it up again. If the word is only capitalized, we
// tested all possibilities, so if it's still negative we can return false.
final String lowerCaseText = text.toLowerCase(mLocale);
if (mService.isValidWord(mLocale, lowerCaseText))
return true;
if (StringUtils.CAPITALIZE_FIRST == capitalizeType)
return false;
// If the lower case version is not in the dictionary, it's still possible
// that we have an all-caps version of a word that needs to be capitalized
// according to the dictionary. E.g. "GERMANS" only exists in the dictionary as "Germans".
return mService.isValidWord(mLocale, StringUtils.capitalizeFirstAndDowncaseRest(lowerCaseText, mLocale));
}
// Note : this must be reentrant
/**
* Gets a list of suggestions for a specific string. This returns a list of possible
* corrections for the text preplaceded as an argument. It may split or group words, and
* even perform grammatical replacedysis.
*/
private SuggestionsInfo onGetSuggestionsInternal(final TextInfo textInfo, final int suggestionsLimit) {
return onGetSuggestionsInternal(textInfo, null, suggestionsLimit);
}
protected SuggestionsInfo onGetSuggestionsInternal(final TextInfo textInfo, final NgramContext ngramContext, final int suggestionsLimit) {
try {
final String text = textInfo.getText().replaceAll(AndroidSpellCheckerService.APOSTROPHE, AndroidSpellCheckerService.SINGLE_QUOTE).replaceAll("^" + quotesRegexp, "").replaceAll(quotesRegexp + "$", "");
if (!mService.hasMainDictionaryForLocale(mLocale)) {
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(false);
}
// Handle special patterns like email, URI, telephone number.
final int checkability = getCheckabilityInScript(text, mScript);
if (CHECKABILITY_CHECKABLE != checkability) {
if (CHECKABILITY_CONTAINS_PERIOD == checkability) {
final String[] splitText = text.split(Constants.REGEXP_PERIOD);
boolean allWordsAreValid = true;
for (final String word : splitText) {
if (!mService.isValidWord(mLocale, word)) {
allWordsAreValid = false;
break;
}
}
if (allWordsAreValid) {
return new SuggestionsInfo(SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO | SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS, new String[] { TextUtils.join(Constants.STRING_SPACE, splitText) });
}
}
return mService.isValidWord(mLocale, text) ? AndroidSpellCheckerService.getInDictEmptySuggestions() : AndroidSpellCheckerService.getNotInDictEmptySuggestions(CHECKABILITY_CONTAINS_PERIOD == checkability);
}
// Handle normal words.
final int capitalizeType = StringUtils.getCapitalizationType(text);
if (isInDictForAnyCapitalization(text, capitalizeType)) {
if (DebugFlags.DEBUG_ENABLED) {
Log.i(TAG, "onGetSuggestionsInternal() : [" + text + "] is a valid word");
}
return AndroidSpellCheckerService.getInDictEmptySuggestions();
}
if (DebugFlags.DEBUG_ENABLED) {
Log.i(TAG, "onGetSuggestionsInternal() : [" + text + "] is NOT a valid word");
}
final Keyboard keyboard = mService.getKeyboardForLocale(mLocale);
if (null == keyboard) {
Log.w(TAG, "onGetSuggestionsInternal() : No keyboard for locale: " + mLocale);
// If there is no keyboard for this locale, don't do any spell-checking.
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(false);
}
final WordComposer composer = new WordComposer();
final int[] codePoints = StringUtils.toCodePointArray(text);
final int[] coordinates;
coordinates = keyboard.getCoordinates(codePoints);
composer.setComposingWord(codePoints, coordinates);
// TODO: Don't gather suggestions if the limit is <= 0 unless necessary
final SuggestionResults suggestionResults = mService.getSuggestionResults(mLocale, composer.getComposedDataSnapshot(), ngramContext, keyboard);
final Result result = getResult(capitalizeType, mLocale, suggestionsLimit, mService.getRecommendedThreshold(), text, suggestionResults);
if (DebugFlags.DEBUG_ENABLED) {
if (result.mSuggestions != null && result.mSuggestions.length > 0) {
final StringBuilder builder = new StringBuilder();
for (String suggestion : result.mSuggestions) {
builder.append(" [");
builder.append(suggestion);
builder.append("]");
}
Log.i(TAG, "onGetSuggestionsInternal() : Suggestions =" + builder);
}
}
// Handle word not in dictionary.
// This is called only once per unique word, so entering multiple
// instances of the same word does not result in more than one call
// to this method.
// Also, upon changing the orientation of the device, this is called
// again for every unique invalid word in the text box.
StatsUtils.onInvalidWordIdentification(text);
final int flags = SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO | (result.mHasRecommendedSuggestions ? SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS : 0);
final SuggestionsInfo retval = new SuggestionsInfo(flags, result.mSuggestions);
mSuggestionsCache.putSuggestionsToCache(text, result.mSuggestions, flags);
return retval;
} catch (RuntimeException e) {
// Don't kill the keyboard if there is a bug in the spell checker
Log.e(TAG, "Exception while spellchecking", e);
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(false);
}
}
private static final clreplaced Result {
public final String[] mSuggestions;
public final boolean mHasRecommendedSuggestions;
public Result(final String[] gatheredSuggestions, final boolean hasRecommendedSuggestions) {
mSuggestions = gatheredSuggestions;
mHasRecommendedSuggestions = hasRecommendedSuggestions;
}
}
private static Result getResult(final int capitalizeType, final Locale locale, final int suggestionsLimit, final float recommendedThreshold, final String originalText, final SuggestionResults suggestionResults) {
if (suggestionResults.isEmpty() || suggestionsLimit <= 0) {
return new Result(null, /* gatheredSuggestions */
false);
}
final ArrayList<String> suggestions = new ArrayList<>();
for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) {
final String suggestion;
if (StringUtils.CAPITALIZE_ALL == capitalizeType) {
suggestion = suggestedWordInfo.mWord.toUpperCase(locale);
} else if (StringUtils.CAPITALIZE_FIRST == capitalizeType) {
suggestion = StringUtils.capitalizeFirstCodePoint(suggestedWordInfo.mWord, locale);
} else {
suggestion = suggestedWordInfo.mWord;
}
suggestions.add(suggestion);
}
StringUtils.removeDupes(suggestions);
// This returns a String[], while toArray() returns an Object[] which cannot be cast
// into a String[].
final List<String> gatheredSuggestionsList = suggestions.subList(0, Math.min(suggestions.size(), suggestionsLimit));
final String[] gatheredSuggestions = gatheredSuggestionsList.toArray(new String[gatheredSuggestionsList.size()]);
final int bestScore = suggestionResults.first().mScore;
final String bestSuggestion = suggestions.get(0);
final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore(originalText, bestSuggestion, bestScore);
final boolean hasRecommendedSuggestions = (normalizedScore > recommendedThreshold);
return new Result(gatheredSuggestions, hasRecommendedSuggestions);
}
/*
* The spell checker acts on its own behalf. That is needed, in particular, to be able to
* access the dictionary files, which the provider restricts to the idenreplacedy of Latin IME.
* Since it's called externally by the application, the spell checker is using the idenreplacedy
* of the application by default unless we clearCallingIdenreplacedy.
* That's what the following method does.
*/
@Override
public SuggestionsInfo onGetSuggestions(final TextInfo textInfo, final int suggestionsLimit) {
long ident = Binder.clearCallingIdenreplacedy();
try {
return onGetSuggestionsInternal(textInfo, suggestionsLimit);
} finally {
Binder.restoreCallingIdenreplacedy(ident);
}
}
}
18
Source : MediaContentObserver.java
with GNU General Public License v3.0
from bcmapp
with GNU General Public License v3.0
from bcmapp
public clreplaced MediaContentObserver {
private ContentObserver mInternalObserver;
private ContentObserver mExternalObserver;
private MediaContentChangeListener listener;
private Context context;
public MediaContentObserver(Context context, Handler handler) {
this.context = context;
mInternalObserver = new ContentObserver(handler) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
if (listener != null) {
listener.onMediaContentChange(MediaStore.Images.Media.INTERNAL_CONTENT_URI);
}
}
};
mExternalObserver = new ContentObserver(handler) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
if (listener != null) {
listener.onMediaContentChange(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
}
}
};
}
public void setChangeListener(MediaContentChangeListener listener) {
this.listener = listener;
if (context != null) {
context.getContentResolver().registerContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, true, mInternalObserver);
context.getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, mExternalObserver);
}
}
public void removeChangeListener() {
this.listener = null;
context.getContentResolver().unregisterContentObserver(mInternalObserver);
context.getContentResolver().unregisterContentObserver(mExternalObserver);
context = null;
}
interface MediaContentChangeListener {
void onMediaContentChange(Uri uri);
}
}
18
Source : InMemoryCursor.java
with Apache License 2.0
from androidx
with Apache License 2.0
from androidx
@Override
public void registerContentObserver(ContentObserver observer) {
mObserverRelay.registerContentObserver(observer);
}
18
Source : InMemoryCursor.java
with Apache License 2.0
from androidx
with Apache License 2.0
from androidx
@Override
public void unregisterContentObserver(ContentObserver observer) {
mObserverRelay.unregisterContentObserver(observer);
}
18
Source : MultiUriCursorWrapper.java
with GNU General Public License v3.0
from AndreAle94
with GNU General Public License v3.0
from AndreAle94
@Override
public void unregisterContentObserver(ContentObserver observer) {
// cursor will unregister all observers when it close
if (!mClosed) {
mContentObservable.unregisterObserver(observer);
}
}
18
Source : SyncManager.java
with Apache License 2.0
from alperali
with Apache License 2.0
from alperali
/**
* This clreplaced manages message sync with the Telephony SmsProvider/MmsProvider.
*/
public clreplaced SyncManager {
private static final String TAG = LogUtil.BUGLE_TAG;
/**
* Record of any user customization to conversation settings
*/
public static clreplaced ConversationCustomization {
private final boolean mArchived;
private final boolean mMuted;
private final boolean mNoVibrate;
private final String mNotificationSoundUri;
public ConversationCustomization(final boolean archived, final boolean muted, final boolean noVibrate, final String notificationSoundUri) {
mArchived = archived;
mMuted = muted;
mNoVibrate = noVibrate;
mNotificationSoundUri = notificationSoundUri;
}
public boolean isArchived() {
return mArchived;
}
public boolean isMuted() {
return mMuted;
}
public boolean noVibrate() {
return mNoVibrate;
}
public String getNotificationSoundUri() {
return mNotificationSoundUri;
}
}
SyncManager() {
}
/**
* Timestamp of in progress sync - used to keep track of whether sync is running
*/
private long mSyncInProgressTimestamp = -1;
/**
* Timestamp of current sync batch upper bound - used to determine if message makes batch dirty
*/
private long mCurrentUpperBoundTimestamp = -1;
/**
* Timestamp of messages inserted since sync batch started - used to determine if batch dirty
*/
private long mMaxRecentChangeTimestamp = -1L;
private final ThreadInfoCache mThreadInfoCache = new ThreadInfoCache();
/**
* User customization to conversations. If this is set, we need to recover them after
* a full sync.
*/
private LongSparseArray<ConversationCustomization> mCustomization = null;
/**
* Start an incremental sync (backed off a few seconds)
*/
public static void sync() {
SyncMessagesAction.sync();
}
/**
* Start an incremental sync (with no backoff)
*/
public static void immediateSync() {
SyncMessagesAction.immediateSync();
}
/**
* Start a full sync (for debugging)
*/
public static void forceSync() {
SyncMessagesAction.fullSync();
}
/**
* Called from data model thread when starting a sync batch
* @param upperBoundTimestamp upper bound timestamp for sync batch
*/
public synchronized void startSyncBatch(final long upperBoundTimestamp) {
replacedert.isTrue(mCurrentUpperBoundTimestamp < 0);
mCurrentUpperBoundTimestamp = upperBoundTimestamp;
mMaxRecentChangeTimestamp = -1L;
}
/**
* Called from data model thread at end of batch to determine if any messages added in window
* @param lowerBoundTimestamp lower bound timestamp for sync batch
* @return true if message added within window from lower to upper bound timestamp of batch
*/
public synchronized boolean isBatchDirty(final long lowerBoundTimestamp) {
replacedert.isTrue(mCurrentUpperBoundTimestamp >= 0);
final long max = mMaxRecentChangeTimestamp;
final boolean dirty = (max >= 0 && max >= lowerBoundTimestamp);
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "SyncManager: Sync batch of messages from " + lowerBoundTimestamp + " to " + mCurrentUpperBoundTimestamp + " is " + (dirty ? "DIRTY" : "clean") + "; max change timestamp = " + mMaxRecentChangeTimestamp);
}
mCurrentUpperBoundTimestamp = -1L;
mMaxRecentChangeTimestamp = -1L;
return dirty;
}
/**
* Called from data model or background worker thread to indicate start of message add process
* (add must complete on that thread before action transitions to new thread/stage)
* @param timestamp timestamp of message being added
*/
public synchronized void onNewMessageInserted(final long timestamp) {
if (mCurrentUpperBoundTimestamp >= 0 && timestamp <= mCurrentUpperBoundTimestamp) {
// Message insert in current sync window
mMaxRecentChangeTimestamp = Math.max(mCurrentUpperBoundTimestamp, timestamp);
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "SyncManager: New message @ " + timestamp + " before upper bound of " + "current sync batch " + mCurrentUpperBoundTimestamp);
}
} else if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "SyncManager: New message @ " + timestamp + " after upper bound of " + "current sync batch " + mCurrentUpperBoundTimestamp);
}
}
/**
* Synchronously checks whether sync is allowed and starts sync if allowed
* @param full - true indicates a full (not incremental) sync operation
* @param startTimestamp - starttimestamp for this sync (if allowed)
* @return - true if sync should start
*/
public synchronized boolean shouldSync(final boolean full, final long startTimestamp) {
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
LogUtil.v(TAG, "SyncManager: Checking shouldSync " + (full ? "full " : "") + "at " + startTimestamp);
}
if (full) {
final long delayUntilFullSync = delayUntilFullSync(startTimestamp);
if (delayUntilFullSync > 0) {
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "SyncManager: Full sync requested for " + startTimestamp + " delayed for " + delayUntilFullSync + " ms");
}
return false;
}
}
if (isSyncing()) {
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "SyncManager: Not allowed to " + (full ? "full " : "") + "sync yet; still running sync started at " + mSyncInProgressTimestamp);
}
return false;
}
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "SyncManager: Starting " + (full ? "full " : "") + "sync at " + startTimestamp);
}
mSyncInProgressTimestamp = startTimestamp;
return true;
}
/**
* Return delay (in ms) until allowed to run a full sync (0 meaning can run immediately)
* @param startTimestamp Timestamp used to start the sync
* @return 0 if allowed to run now, else delay in ms
*/
public long delayUntilFullSync(final long startTimestamp) {
final BugleGservices bugleGservices = BugleGservices.get();
final BuglePrefs prefs = BuglePrefs.getApplicationPrefs();
final long lastFullSyncTime = prefs.getLong(BuglePrefsKeys.LAST_FULL_SYNC_TIME, -1L);
final long smsFullSyncBackoffTimeMillis = bugleGservices.getLong(BugleGservicesKeys.SMS_FULL_SYNC_BACKOFF_TIME_MILLIS, BugleGservicesKeys.SMS_FULL_SYNC_BACKOFF_TIME_MILLIS_DEFAULT);
final long noFullSyncBefore = (lastFullSyncTime < 0 ? startTimestamp : lastFullSyncTime + smsFullSyncBackoffTimeMillis);
final long delayUntilFullSync = noFullSyncBefore - startTimestamp;
if (delayUntilFullSync > 0) {
return delayUntilFullSync;
}
return 0;
}
/**
* Check if sync currently in progress (public for replacederts/logging).
*/
public synchronized boolean isSyncing() {
return (mSyncInProgressTimestamp >= 0);
}
/**
* Check if sync batch should be in progress - compares upperBound with in memory value
* @param upperBoundTimestamp - upperbound timestamp for sync batch
* @return - true if timestamps match (otherwise batch is orphan from older process)
*/
public synchronized boolean isSyncing(final long upperBoundTimestamp) {
replacedert.isTrue(upperBoundTimestamp >= 0);
return (upperBoundTimestamp == mCurrentUpperBoundTimestamp);
}
/**
* Check if sync has completed for the first time.
*/
public boolean getHasFirstSyncCompleted() {
final BuglePrefs prefs = BuglePrefs.getApplicationPrefs();
return prefs.getLong(BuglePrefsKeys.LAST_SYNC_TIME, BuglePrefsKeys.LAST_SYNC_TIME_DEFAULT) != BuglePrefsKeys.LAST_SYNC_TIME_DEFAULT;
}
/**
* Called once sync is complete
*/
public synchronized void complete() {
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "SyncManager: Sync started at " + mSyncInProgressTimestamp + " marked as complete");
}
mSyncInProgressTimestamp = -1L;
// Conversation customization only used once
mCustomization = null;
}
private final ContentObserver mMmsSmsObserver = new TelephonyMessagesObserver();
private boolean mSyncOnChanges = false;
private boolean mNotifyOnChanges = false;
/**
* Register content observer when necessary and kick off a catch up sync
*/
public void updateSyncObserver(final Context context) {
registerObserver(context);
// Trigger an sms sync in case we missed and messages before registering this observer or
// becoming the SMS provider.
immediateSync();
}
private void registerObserver(final Context context) {
if (!PhoneUtils.getDefault().isDefaultSmsApp()) {
// Not default SMS app - need to actively monitor telephony but not notify
mNotifyOnChanges = false;
mSyncOnChanges = true;
} else if (OsUtil.isSecondaryUser()) {
// Secondary users default SMS app - need to actively monitor telephony and notify
mNotifyOnChanges = true;
mSyncOnChanges = true;
} else {
// Primary users default SMS app - don't monitor telephony (most changes from this app)
mNotifyOnChanges = false;
mSyncOnChanges = false;
if (context.getPackageManager().hreplacedystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
// This is default SMS app but on Auto platform, even default SMS app needs
// to be notified of changes because Bluetooth makes changes to Sms database
// (thru ContentProvider). Content Change notifications help the default SMS app
// refresh display with changes, whenever Bluetooth changes data in SMS db.
mNotifyOnChanges = true;
mSyncOnChanges = false;
}
}
if (mNotifyOnChanges || mSyncOnChanges) {
context.getContentResolver().registerContentObserver(Telephony.MmsSms.CONTENT_URI, true, mMmsSmsObserver);
} else {
context.getContentResolver().unregisterContentObserver(mMmsSmsObserver);
}
}
public synchronized void setCustomization(final LongSparseArray<ConversationCustomization> customization) {
this.mCustomization = customization;
}
public synchronized ConversationCustomization getCustomizationForThread(final long threadId) {
if (mCustomization != null) {
return mCustomization.get(threadId);
}
return null;
}
public static void resetLastSyncTimestamps() {
final BuglePrefs prefs = BuglePrefs.getApplicationPrefs();
prefs.putLong(BuglePrefsKeys.LAST_FULL_SYNC_TIME, BuglePrefsKeys.LAST_FULL_SYNC_TIME_DEFAULT);
prefs.putLong(BuglePrefsKeys.LAST_SYNC_TIME, BuglePrefsKeys.LAST_SYNC_TIME_DEFAULT);
}
private clreplaced TelephonyMessagesObserver extends ContentObserver {
public TelephonyMessagesObserver() {
// Just run on default thread
super(null);
}
// Implement the onChange(boolean) method to delegate the change notification to
// the onChange(boolean, Uri) method to ensure correct operation on older versions
// of the framework that did not have the onChange(boolean, Uri) method.
@Override
public void onChange(final boolean selfChange) {
onChange(selfChange, null);
}
// Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
@Override
public void onChange(final boolean selfChange, final Uri uri) {
// Handle change.
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
LogUtil.v(TAG, "SyncManager: Sms/Mms DB changed @" + System.currentTimeMillis() + " for " + (uri == null ? "<unk>" : uri.toString()) + " " + mSyncOnChanges + "/" + mNotifyOnChanges);
}
if (mSyncOnChanges) {
// If sync is already running this will do nothing - but at end of each sync
// action there is a check for recent messages that should catch new changes.
SyncManager.immediateSync();
}
if (mNotifyOnChanges) {
// TODO: Secondary users are not going to get notifications
}
}
}
public ThreadInfoCache getThreadInfoCache() {
return mThreadInfoCache;
}
public static clreplaced ThreadInfoCache {
// Cache of thread->conversationId map
private final LongSparseArray<String> mThreadToConversationId = new LongSparseArray<String>();
// Cache of thread->recipients map
private final LongSparseArray<List<String>> mThreadToRecipients = new LongSparseArray<List<String>>();
// Remember the conversation ids that need to be archived
private final HashSet<String> mArchivedConversations = new HashSet<>();
public synchronized void clear() {
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "SyncManager: Cleared ThreadInfoCache");
}
mThreadToConversationId.clear();
mThreadToRecipients.clear();
mArchivedConversations.clear();
}
public synchronized boolean isArchived(final String conversationId) {
return mArchivedConversations.contains(conversationId);
}
/**
* Get or create a conversation based on the message's thread id
*
* @param threadId The message's thread
* @param refSubId The subId used for normalizing phone numbers in the thread
* @param customization The user setting customization to the conversation if any
* @return The existing conversation id or new conversation id
*/
public synchronized String getOrCreateConversation(final DatabaseWrapper db, final long threadId, int refSubId, final ConversationCustomization customization) {
// This function has several components which need to be atomic.
replacedert.isTrue(db.getDatabase().inTransaction());
// If we already have this conversation ID in our local map, just return it
String conversationId = mThreadToConversationId.get(threadId);
if (conversationId != null) {
return conversationId;
}
final List<String> recipients = getThreadRecipients(threadId);
final ArrayList<ParticipantData> participants = BugleDatabaseOperations.getConversationParticipantsFromRecipients(recipients, refSubId);
if (customization != null) {
// There is user customization we need to recover
conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId, customization.isArchived(), participants, customization.isMuted(), customization.noVibrate(), customization.getNotificationSoundUri());
if (customization.isArchived()) {
mArchivedConversations.add(conversationId);
}
} else {
conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId, false, /*archived*/
participants, false, /*noNotification*/
false, /*noVibrate*/
null);
}
if (conversationId != null) {
mThreadToConversationId.put(threadId, conversationId);
return conversationId;
}
return null;
}
/**
* Load the recipients of a thread from telephony provider. If we fail, use
* a predefined unknown recipient. This should not return null.
*
* @param threadId
*/
public synchronized List<String> getThreadRecipients(final long threadId) {
List<String> recipients = mThreadToRecipients.get(threadId);
if (recipients == null) {
recipients = MmsUtils.getRecipientsByThread(threadId);
if (recipients != null && recipients.size() > 0) {
mThreadToRecipients.put(threadId, recipients);
}
}
if (recipients == null || recipients.isEmpty()) {
LogUtil.w(TAG, "SyncManager : using unknown sender since thread " + threadId + " couldn't find any recipients.");
// We want to try our best to load the messages,
// so if recipient info is broken, try to fix it with unknown recipient
recipients = Lists.newArrayList();
recipients.add(ParticipantData.getUnknownSenderDestination());
}
return recipients;
}
}
}
17
Source : ReadSmsService.java
with Apache License 2.0
from xiong-it
with Apache License 2.0
from xiong-it
/**
* 短信验证码读取服务
*/
public clreplaced ReadSmsService extends Service {
private static final String TAG = ReadSmsService.clreplaced.getSimpleName();
// 接收到短信时的action
private static final String SMS_RECEIVED_ACTION = Telephony.Sms.Intents.SMS_RECEIVED_ACTION;
// API level>=23,可直接使用Telephony.Sms.Inbox.CONTENT_URI
private static final String SMS_INBOX_URI = "content://sms/inbox";
// API level>=23,可直接使用Telephony.Sms.CONTENT_URI
private static final String SMS_URI = "content://sms";
static final String[] PROJECTION = new String[] { Telephony.Sms._ID, Telephony.Sms.ADDRESS, Telephony.Sms.BODY, Telephony.Sms.DATE };
public static final String EXTRAS_MESSAGER = "tech.michaelx.verifycode.ReadSmsService.EXTRAS_MESSAGER";
public static final String EXTRAS_COFIG = "tech.michaelx.verifycode.ReadSmsService.EXTRAS_COFIG";
public static final int RECEIVER_SMS_CODE_MSG = 0;
public static final int OBSERVER_SMS_CODE_MSG = 1;
private Messenger mMessenger;
private CodeConfig mCodeConfig;
/**
* 读取未读短信,用以填写验证码
*/
private ContentObserver mReadSmsObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Cursor cursor = getContentResolver().query(Uri.parse(SMS_INBOX_URI), PROJECTION, Telephony.Sms.READ + "=?", new String[] { "0" }, Telephony.Sms.Inbox.DEFAULT_SORT_ORDER);
getSmsCodeFromObserver(cursor);
}
};
/**
* 短信广播接收者
*/
private BroadcastReceiver mReadSmsCodeReceiver = new ReadSmsCodeReceiver();
private clreplaced ReadSmsCodeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(SMS_RECEIVED_ACTION)) {
getSmsCodeFromReceiver(intent);
}
}
}
public ReadSmsService() {
super();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
Bundle bundle = intent.getExtras();
if (bundle == null) {
Log.e("AutoInputAuthCode", "bundle = null");
} else {
register();
mMessenger = bundle.getParcelable(EXTRAS_MESSAGER);
mCodeConfig = bundle.getParcelable(EXTRAS_COFIG);
}
}
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
unRegister();
}
/**
* 包访问级别:提高性能
* 从接收者中得到短信验证码
*
* @param intent
*/
void getSmsCodeFromReceiver(Intent intent) {
SmsMessage[] messages = null;
if (Build.VERSION.SDK_INT >= 19) {
messages = android.provider.Telephony.Sms.Intents.getMessagesFromIntent(intent);
if (messages == null)
return;
} else {
messages = getSmsUnder19(intent);
if (messages == null)
return;
}
if (messages.length > 0) {
for (int i = 0; i < messages.length; i++) {
SmsMessage sms = messages[i];
String smsSender = sms.getOriginatingAddress();
String smsBody = sms.getMessageBody();
if (checkSmsSender(smsSender) && checkSmsBody(smsBody)) {
String smsCode = parseSmsBody(smsBody);
sendMsg2Register(OBSERVER_SMS_CODE_MSG, smsCode);
break;
}
}
}
}
@Nullable
private SmsMessage[] getSmsUnder19(Intent intent) {
SmsMessage[] messages;
Bundle bundle = intent.getExtras();
// 相关链接:https://developer.android.com/reference/android/provider/Telephony.Sms.Intents.html#SMS_DELIVER_ACTION
Object[] pdus = (Object[]) bundle.get("pdus");
if ((pdus == null) || (pdus.length == 0)) {
return null;
}
messages = new SmsMessage[pdus.length];
for (int i = 0; i < pdus.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
return messages;
}
/**
* 包访问级别:提高性能
* 从内容观察者得到短信验证码
*
* @param cursor
*/
void getSmsCodeFromObserver(Cursor cursor) {
if (cursor == null)
return;
while (cursor.moveToNext()) {
String address = cursor.getString(cursor.getColumnIndex(Telephony.Sms.ADDRESS));
String smsBody = cursor.getString(cursor.getColumnIndex(Telephony.Sms.BODY));
if (checkSmsSender(address) && checkSmsBody(smsBody)) {
String smsCode = parseSmsBody(smsBody);
sendMsg2Register(RECEIVER_SMS_CODE_MSG, smsCode);
break;
}
}
closeCursor(cursor);
}
private void closeCursor(Cursor cursor) {
if (cursor == null || cursor.isClosed())
return;
if (!cursor.isClosed()) {
cursor.close();
}
}
/**
* @param smsBody
* @return
*/
private boolean checkSmsBody(String smsBody) {
if (!TextUtils.isEmpty(mCodeConfig.getSmsBodyStart()) && !TextUtils.isEmpty(mCodeConfig.getSmsBodyContains())) {
return smsBody.startsWith(mCodeConfig.getSmsBodyStart()) && smsBody.contains(mCodeConfig.getSmsBodyContains());
} else if (!TextUtils.isEmpty(mCodeConfig.getSmsBodyStart())) {
return smsBody.startsWith(mCodeConfig.getSmsBodyStart());
} else if (!TextUtils.isEmpty(mCodeConfig.getSmsBodyContains())) {
return smsBody.contains(mCodeConfig.getSmsBodyContains());
} else {
return true;
}
}
/**
* @param smsSender
* @return
*/
private boolean checkSmsSender(String smsSender) {
if (mCodeConfig.getSmsFrom() != 0) {
return smsSender.equals(String.valueOf(mCodeConfig.getSmsFrom()));
}
return smsSender.contains(String.valueOf(mCodeConfig.getSmsFromStart()));
}
/**
* 注册广播接收者,内容观察者
*/
private void register() {
registerReceiver();
registerObserver();
}
/**
* 注册广播接收者
*/
private void registerReceiver() {
IntentFilter filter = new IntentFilter(SMS_RECEIVED_ACTION);
filter.addAction(SMS_RECEIVED_ACTION);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
registerReceiver(mReadSmsCodeReceiver, filter);
}
/**
* 注册内容观察者
*/
private void registerObserver() {
getContentResolver().registerContentObserver(Uri.parse(SMS_URI), true, mReadSmsObserver);
}
/**
* 注销广播接收者,内容观察者
*/
private void unRegister() {
unRegisterReceiver();
unRegisterObserver();
}
/**
* 注销广播接收者
*/
private void unRegisterReceiver() {
if (mReadSmsCodeReceiver == null)
return;
unregisterReceiver(mReadSmsCodeReceiver);
mReadSmsCodeReceiver = null;
}
/**
* 注销内容观察者
*/
private void unRegisterObserver() {
if (mReadSmsObserver == null)
return;
getContentResolver().unregisterContentObserver(mReadSmsObserver);
mReadSmsObserver = null;
}
/**
* 解析短信得到验证码
*
* @param smsBody
* @return
*/
private String parseSmsBody(String smsBody) {
int len = mCodeConfig.getCodeLen();
// 匹配规则为短信中的连续数字
String regex = new String("(\\d{" + len + "})");
String smsCode = "";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(smsBody);
while (matcher.find()) {
smsCode = matcher.group(0);
}
return smsCode;
}
/**
* 发送消息到注册界面
*
* @param msgWhat
* @param msgObj
*/
private void sendMsg2Register(int msgWhat, String msgObj) {
if (mMessenger != null) {
Message msg = Message.obtain();
msg.what = msgWhat;
msg.obj = msgObj;
try {
mMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
} finally {
stopSelf();
}
}
}
}
17
Source : SettingsProviderTest.java
with Apache License 2.0
from RealMoMo
with Apache License 2.0
from RealMoMo
private void setSettingAndreplacedertSuccessfulChange(Runnable setCommand, final int type, final String name, final String value, final int userId) throws Exception {
ContentResolver contentResolver = getContext().getContentResolver();
final Uri settingUri = getBaseUriForType(type);
final AtomicBoolean success = new AtomicBoolean();
ContentObserver contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
public void onChange(boolean selfChange, Uri changeUri, int changeId) {
Log.i(LOG_TAG, "onChange(" + selfChange + ", " + changeUri + ", " + changeId + ")");
replacedertEquals("Wrong change Uri", changeUri, settingUri);
replacedertEquals("Wrong user id", userId, changeId);
String changeValue = getStringViaFrontEndApiSetting(type, name, userId);
replacedertEquals("Wrong setting value", value, changeValue);
success.set(true);
synchronized (mLock) {
mLock.notifyAll();
}
}
};
contentResolver.registerContentObserver(settingUri, false, contentObserver, userId);
try {
setCommand.run();
final long startTimeMillis = SystemClock.uptimeMillis();
synchronized (mLock) {
if (success.get()) {
return;
}
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
fail("Could not change setting for " + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
}
final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS - elapsedTimeMillis;
try {
mLock.wait(remainingTimeMillis);
} catch (InterruptedException ie) {
/* ignore */
}
}
} finally {
contentResolver.unregisterContentObserver(contentObserver);
}
}
17
Source : PluginProviderClient.java
with Apache License 2.0
from Qihoo360
with Apache License 2.0
from Qihoo360
/**
* @deprecated
*/
public static void registerContentObserver(Context c, Uri uri, boolean notifyForDescendents, ContentObserver observer) {
com.qihoo360.replugin.component.provider.PluginProviderClient.registerContentObserver(c, uri, notifyForDescendents, observer);
}
17
Source : PluginProviderClient.java
with Apache License 2.0
from Qihoo360
with Apache License 2.0
from Qihoo360
/**
* @deprecated
*/
public static void notifyChange(Context c, Uri uri, ContentObserver observer) {
com.qihoo360.replugin.component.provider.PluginProviderClient.notifyChange(c, uri, observer);
}
17
Source : PluginProviderClient.java
with Apache License 2.0
from Qihoo360
with Apache License 2.0
from Qihoo360
/**
* @deprecated
*/
public static void notifyChange(Context c, Uri uri, ContentObserver observer, boolean b) {
com.qihoo360.replugin.component.provider.PluginProviderClient.notifyChange(c, uri, observer, b);
}
17
Source : ApmProvider.java
with Apache License 2.0
from Qihoo360
with Apache License 2.0
from Qihoo360
private void notifyChange(Uri uri, ContentObserver observer) {
try {
getContext().getContentResolver().notifyChange(uri, observer);
} catch (Exception e) {
if (Env.DEBUG) {
LogX.d(Env.TAG, "notifyChange ex : " + Log.getStackTraceString(e));
}
}
}
17
Source : HapticFeedbackController.java
with Apache License 2.0
from philliphsu
with Apache License 2.0
from philliphsu
/**
* A simple utility clreplaced to handle haptic feedback.
*/
public clreplaced HapticFeedbackController {
private static final int VIBRATE_DELAY_MS = 125;
private static final int VIBRATE_LENGTH_MS = 5;
private static boolean checkGlobalSetting(Context context) {
return Settings.System.getInt(context.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 1;
}
private final Context mContext;
private final ContentObserver mContentObserver;
private Vibrator mVibrator;
private boolean mIsGloballyEnabled;
private long mLastVibrate;
public HapticFeedbackController(Context context) {
mContext = context;
mContentObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
mIsGloballyEnabled = checkGlobalSetting(mContext);
}
};
}
/**
* Call to setup the controller.
*/
public void start() {
mVibrator = (Vibrator) mContext.getSystemService(Service.VIBRATOR_SERVICE);
// Setup a listener for changes in haptic feedback settings
mIsGloballyEnabled = checkGlobalSetting(mContext);
Uri uri = Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED);
mContext.getContentResolver().registerContentObserver(uri, false, mContentObserver);
}
/**
* Call this when you don't need the controller anymore.
*/
public void stop() {
mVibrator = null;
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
}
/**
* Try to vibrate. To prevent this becoming a single continuous vibration, nothing will
* happen if we have vibrated very recently.
*/
public void tryVibrate() {
if (mVibrator != null && mIsGloballyEnabled) {
long now = SystemClock.uptimeMillis();
// We want to try to vibrate each individual tick discretely.
if (now - mLastVibrate >= VIBRATE_DELAY_MS) {
mVibrator.vibrate(VIBRATE_LENGTH_MS);
mLastVibrate = now;
}
}
}
}
17
Source : ContentResolver.java
with Apache License 2.0
from oasisfeng
with Apache License 2.0
from oasisfeng
@RequiresApi(N)
public void notifyChange(Uri uri, ContentObserver observer, int flags) {
throw new RuntimeException("Stub!");
}
17
Source : StickerPackPreviewViewModel.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
final clreplaced StickerPackPreviewViewModel extends ViewModel {
private final Application application;
private final StickerPackPreviewRepository previewRepository;
private final StickerManagementRepository managementRepository;
private final MutableLiveData<Optional<StickerManifestResult>> stickerManifest;
private final ContentObserver packObserver;
private String packId;
private String packKey;
private StickerPackPreviewViewModel(@NonNull Application application, @NonNull StickerPackPreviewRepository previewRepository, @NonNull StickerManagementRepository managementRepository) {
this.application = application;
this.previewRepository = previewRepository;
this.managementRepository = managementRepository;
this.stickerManifest = new MutableLiveData<>();
this.packObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
if (!TextUtils.isEmpty(packId) && !TextUtils.isEmpty(packKey)) {
previewRepository.getStickerManifest(packId, packKey, stickerManifest::postValue);
}
}
};
application.getContentResolver().registerContentObserver(DatabaseContentProviders.StickerPack.CONTENT_URI, true, packObserver);
}
LiveData<Optional<StickerManifestResult>> getStickerManifest(@NonNull String packId, @NonNull String packKey) {
this.packId = packId;
this.packKey = packKey;
previewRepository.getStickerManifest(packId, packKey, stickerManifest::postValue);
return stickerManifest;
}
void onInstallClicked() {
managementRepository.installStickerPack(packId, packKey, true);
}
void onRemoveClicked() {
managementRepository.uninstallStickerPack(packId, packKey);
}
@Override
protected void onCleared() {
application.getContentResolver().unregisterContentObserver(packObserver);
}
static clreplaced Factory extends ViewModelProvider.NewInstanceFactory {
private final Application application;
private final StickerPackPreviewRepository previewRepository;
private final StickerManagementRepository managementRepository;
Factory(@NonNull Application application, @NonNull StickerPackPreviewRepository previewRepository, @NonNull StickerManagementRepository managementRepository) {
this.application = application;
this.previewRepository = previewRepository;
this.managementRepository = managementRepository;
}
@Override
@NonNull
public <T extends ViewModel> T create(@NonNull Clreplaced<T> modelClreplaced) {
// noinspection ConstantConditions
return modelClreplaced.cast(new StickerPackPreviewViewModel(application, previewRepository, managementRepository));
}
}
}
17
Source : StickerManagementViewModel.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
final clreplaced StickerManagementViewModel extends ViewModel {
private final Application application;
private final StickerManagementRepository repository;
private final MutableLiveData<PackResult> packs;
private final ContentObserver observer;
private StickerManagementViewModel(@NonNull Application application, @NonNull StickerManagementRepository repository) {
this.application = application;
this.repository = repository;
this.packs = new MutableLiveData<>();
this.observer = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
repository.deleteOrphanedStickerPacks();
repository.getStickerPacks(packs::postValue);
}
};
application.getContentResolver().registerContentObserver(DatabaseContentProviders.StickerPack.CONTENT_URI, true, observer);
}
void init() {
repository.deleteOrphanedStickerPacks();
repository.fetchUnretrievedReferencePacks();
}
void onVisible() {
repository.deleteOrphanedStickerPacks();
}
@NonNull
LiveData<PackResult> getStickerPacks() {
repository.getStickerPacks(packs::postValue);
return packs;
}
void onStickerPackUninstallClicked(@NonNull String packId, @NonNull String packKey) {
repository.uninstallStickerPack(packId, packKey);
}
void onStickerPackInstallClicked(@NonNull String packId, @NonNull String packKey) {
repository.installStickerPack(packId, packKey, false);
}
void onOrderChanged(List<StickerPackRecord> packsInOrder) {
repository.setPackOrder(packsInOrder);
}
@Override
protected void onCleared() {
application.getContentResolver().unregisterContentObserver(observer);
}
static clreplaced Factory extends ViewModelProvider.NewInstanceFactory {
private final Application application;
private final StickerManagementRepository repository;
Factory(@NonNull Application application, @NonNull StickerManagementRepository repository) {
this.application = application;
this.repository = repository;
}
@Override
@NonNull
public <T extends ViewModel> T create(@NonNull Clreplaced<T> modelClreplaced) {
// noinspection ConstantConditions
return modelClreplaced.cast(new StickerManagementViewModel(application, repository));
}
}
}
17
Source : ViewOnceMessageViewModel.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
clreplaced ViewOnceMessageViewModel extends ViewModel {
private static final String TAG = Log.tag(ViewOnceMessageViewModel.clreplaced);
private final Application application;
private final ViewOnceMessageRepository repository;
private final MutableLiveData<Optional<MmsMessageRecord>> message;
private final ContentObserver observer;
private ViewOnceMessageViewModel(@NonNull Application application, long messageId, @NonNull ViewOnceMessageRepository repository) {
this.application = application;
this.repository = repository;
this.message = new MutableLiveData<>();
this.observer = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
repository.getMessage(messageId, optionalMessage -> onMessageRetrieved(optionalMessage));
}
};
repository.getMessage(messageId, message -> {
if (message.isPresent()) {
Uri uri = DatabaseContentProviders.Conversation.getUriForThread(message.get().getThreadId());
application.getContentResolver().registerContentObserver(uri, true, observer);
}
onMessageRetrieved(message);
});
}
@NonNull
LiveData<Optional<MmsMessageRecord>> getMessage() {
return message;
}
@Override
protected void onCleared() {
application.getContentResolver().unregisterContentObserver(observer);
}
private void onMessageRetrieved(@NonNull Optional<MmsMessageRecord> optionalMessage) {
Util.runOnMain(() -> {
MmsMessageRecord current = message.getValue() != null ? message.getValue().orNull() : null;
MmsMessageRecord proposed = optionalMessage.orNull();
if (current != null && proposed != null && current.getId() == proposed.getId()) {
Log.d(TAG, "Same ID -- skipping update");
} else {
message.setValue(optionalMessage);
}
});
}
static clreplaced Factory extends ViewModelProvider.NewInstanceFactory {
private final Application application;
private final long messageId;
private final ViewOnceMessageRepository repository;
Factory(@NonNull Application application, long messageId, @NonNull ViewOnceMessageRepository repository) {
this.application = application;
this.messageId = messageId;
this.repository = repository;
}
@Override
@NonNull
public <T extends ViewModel> T create(@NonNull Clreplaced<T> modelClreplaced) {
// noinspection ConstantConditions
return modelClreplaced.cast(new ViewOnceMessageViewModel(application, messageId, repository));
}
}
}
17
Source : MessageRecordLiveData.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
final clreplaced MessageRecordLiveData extends LiveData<MessageRecord> {
private final Context context;
private final String type;
private final Long messageId;
private final ContentObserver obs;
@Nullable
private Cursor cursor;
MessageRecordLiveData(Context context, String type, Long messageId) {
this.context = context;
this.type = type;
this.messageId = messageId;
obs = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
SignalExecutors.BOUNDED.execute(() -> resetCursor());
}
};
}
@Override
protected void onActive() {
retrieveMessageRecord();
}
@Override
protected void onInactive() {
SignalExecutors.BOUNDED.execute(this::destroyCursor);
}
private void retrieveMessageRecord() {
SignalExecutors.BOUNDED.execute(this::retrieveMessageRecordActual);
}
@WorkerThread
private synchronized void destroyCursor() {
if (cursor != null) {
cursor.unregisterContentObserver(obs);
cursor.close();
cursor = null;
}
}
@WorkerThread
private synchronized void resetCursor() {
destroyCursor();
retrieveMessageRecord();
}
@WorkerThread
private synchronized void retrieveMessageRecordActual() {
if (cursor != null) {
return;
}
switch(type) {
case MmsSmsDatabase.SMS_TRANSPORT:
handleSms();
break;
case MmsSmsDatabase.MMS_TRANSPORT:
handleMms();
break;
default:
throw new replacedertionError("no valid message type specified");
}
}
@WorkerThread
private synchronized void handleSms() {
final MessageDatabase db = DatabaseFactory.getSmsDatabase(context);
final Cursor cursor = db.getVerboseMessageCursor(messageId);
final MessageRecord record = SmsDatabase.readerFor(cursor).getNext();
postValue(record);
cursor.registerContentObserver(obs);
this.cursor = cursor;
}
@WorkerThread
private synchronized void handleMms() {
final MessageDatabase db = DatabaseFactory.getMmsDatabase(context);
final Cursor cursor = db.getVerboseMessageCursor(messageId);
final MessageRecord record = MmsDatabase.readerFor(cursor).getNext();
postValue(record);
cursor.registerContentObserver(obs);
this.cursor = cursor;
}
}
17
Source : CursorList.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
@Override
public void unregisterContentObserver(@NonNull ContentObserver observer) {
cursor.unregisterContentObserver(observer);
}
17
Source : CursorList.java
with GNU General Public License v3.0
from mollyim
with GNU General Public License v3.0
from mollyim
@Override
public void registerContentObserver(@NonNull ContentObserver observer) {
cursor.registerContentObserver(observer);
}
17
Source : HapticFeedbackController.java
with Apache License 2.0
from mohsenjahani
with Apache License 2.0
from mohsenjahani
/**
* A simple utility clreplaced to handle haptic feedback.
*/
public clreplaced HapticFeedbackController {
private static final int VIBRATE_DELAY_MS = 125;
private static final int VIBRATE_LENGTH_MS = 50;
private static boolean checkGlobalSetting(Context context) {
return Settings.System.getInt(context.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 1;
}
private final Context mContext;
private final ContentObserver mContentObserver;
private Vibrator mVibrator;
private boolean mIsGloballyEnabled;
private long mLastVibrate;
public HapticFeedbackController(Context context) {
mContext = context;
mContentObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
mIsGloballyEnabled = checkGlobalSetting(mContext);
}
};
}
/**
* Call to setup the controller.
*/
public void start() {
if (hasVibratePermission(mContext)) {
mVibrator = (Vibrator) mContext.getSystemService(Service.VIBRATOR_SERVICE);
}
// Setup a listener for changes in haptic feedback settings
mIsGloballyEnabled = checkGlobalSetting(mContext);
Uri uri = Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED);
mContext.getContentResolver().registerContentObserver(uri, false, mContentObserver);
}
/**
* Method to verify that vibrate permission has been granted.
*
* Allows users of the library to disabled vibrate support if desired.
* @return true if Vibrate permission has been granted
*/
private boolean hasVibratePermission(Context context) {
PackageManager pm = context.getPackageManager();
int hasPerm = pm.checkPermission(android.Manifest.permission.VIBRATE, context.getPackageName());
return hasPerm == PackageManager.PERMISSION_GRANTED;
}
/**
* Call this when you don't need the controller anymore.
*/
public void stop() {
mVibrator = null;
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
}
/**
* Try to vibrate. To prevent this becoming a single continuous vibration, nothing will
* happen if we have vibrated very recently.
*/
public void tryVibrate() {
if (mVibrator != null && mIsGloballyEnabled) {
long now = SystemClock.uptimeMillis();
// We want to try to vibrate each individual tick discretely.
if (now - mLastVibrate >= VIBRATE_DELAY_MS) {
mVibrator.vibrate(VIBRATE_LENGTH_MS);
mLastVibrate = now;
}
}
}
}
See More Examples