(CursorWindow.java:120)
at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:202)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:147)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:140)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:232)
at android.database.AbstractCursor.moveToNext(AbstractCursor.java:281)
at androidx.room.InvalidationTracker$1.checkUpdatedTable(SourceFile:417)
at androidx.room.InvalidationTracker$1.run(SourceFile:388)
at androidx.work.impl.utils.SerialExecutor$Task.run(SourceFile:91)
*/
return false;
if (ex instanceof SQLiteFullException) // database or disk is full (code 13 SQLITE_FULL)
return false;
if ("android.util.SuperNotCalledException".equals(ex.getClass().getName()))
/*
android.util.SuperNotCalledException: Activity {eu.faircode.email/eu.faircode.email.ActivityView} did not call through to super.onResume()
at android.app.Activity.performResume(Activity.java:7304)
at android.app.ActivityThread.performNewIntents(ActivityThread.java:3165)
at android.app.ActivityThread.handleNewIntent(ActivityThread.java:3180)
at android.app.servertransaction.NewIntentItem.execute(NewIntentItem.java:49)
*/
return false;
if ("android.view.WindowManager$InvalidDisplayException".equals(ex.getClass().getName()))
/*
android.view.WindowManager$InvalidDisplayException: Unable to add window android.view.ViewRootImpl$W@d7b5a0b -- the specified display can not be found
at android.view.ViewRootImpl.setView(ViewRootImpl.java:854)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
at android.widget.PopupWindow.invokePopup(PopupWindow.java:1492)
at android.widget.PopupWindow.showAsDropDown(PopupWindow.java:1342)
at androidx.appcompat.widget.AppCompatPopupWindow.showAsDropDown(SourceFile:77)
at androidx.core.widget.PopupWindowCompat.showAsDropDown(SourceFile:69)
at androidx.appcompat.widget.ListPopupWindow.show(SourceFile:754)
at androidx.appcompat.view.menu.CascadingMenuPopup.showMenu(SourceFile:486)
at androidx.appcompat.view.menu.CascadingMenuPopup.show(SourceFile:265)
at androidx.appcompat.view.menu.MenuPopupHelper.showPopup(SourceFile:290)
at androidx.appcompat.view.menu.MenuPopupHelper.tryShow(SourceFile:177)
at androidx.appcompat.widget.ActionMenuPresenter$OpenOverflowRunnable.run(SourceFile:792)
*/
return false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
if (ex instanceof RuntimeException && ex.getCause() instanceof DeadObjectException)
return false;
if (BuildConfig.BETA_RELEASE)
return true;
while (ex != null) {
for (StackTraceElement ste : ex.getStackTrace())
if (ste.getClassName().startsWith(BuildConfig.APPLICATION_ID))
return true;
ex = ex.getCause();
}
return false;
}
static String formatThrowable(Throwable ex) {
return formatThrowable(ex, true);
}
static String formatThrowable(Throwable ex, boolean santize) {
return formatThrowable(ex, " ", santize);
}
static String formatThrowable(Throwable ex, String separator, boolean sanitize) {
if (sanitize) {
if (ex instanceof MessageRemovedException)
return null;
if (ex instanceof AuthenticationFailedException &&
ex.getCause() instanceof SocketException)
return null;
if (ex instanceof MessagingException &&
("connection failure".equals(ex.getMessage()) ||
"failed to create new store connection".equals(ex.getMessage())))
return null;
if (ex instanceof MessagingException &&
ex.getCause() instanceof ConnectionException &&
ex.getCause().getMessage() != null &&
(ex.getCause().getMessage().contains("Read error") ||
ex.getCause().getMessage().contains("Write error") ||
ex.getCause().getMessage().contains("Unexpected end of ZLIB input stream") ||
ex.getCause().getMessage().contains("Socket is closed")))
return null;
// javax.mail.MessagingException: AU3 BAD User is authenticated but not connected.;
// nested exception is:
// com.sun.mail.iap.BadCommandException: AU3 BAD User is authenticated but not connected.
// javax.mail.MessagingException: AU3 BAD User is authenticated but not connected.;
// nested exception is:
// com.sun.mail.iap.BadCommandException: AU3 BAD User is authenticated but not connected.
// at com.sun.mail.imap.IMAPFolder.logoutAndThrow(SourceFile:1156)
// at com.sun.mail.imap.IMAPFolder.open(SourceFile:1063)
// at com.sun.mail.imap.IMAPFolder.open(SourceFile:977)
// at eu.faircode.email.ServiceSynchronize.monitorAccount(SourceFile:890)
// at eu.faircode.email.ServiceSynchronize.access$1500(SourceFile:85)
// at eu.faircode.email.ServiceSynchronize$7$1.run(SourceFile:627)
// at java.lang.Thread.run(Thread.java:764)
// Caused by: com.sun.mail.iap.BadCommandException: AU3 BAD User is authenticated but not connected.
// at com.sun.mail.iap.Protocol.handleResult(SourceFile:415)
// at com.sun.mail.imap.protocol.IMAPProtocol.select(SourceFile:1230)
// at com.sun.mail.imap.IMAPFolder.open(SourceFile:1034)
if (ex instanceof MessagingException &&
ex.getCause() instanceof BadCommandException &&
ex.getCause().getMessage() != null &&
ex.getCause().getMessage().contains("User is authenticated but not connected"))
return null;
if (ex instanceof IOException &&
ex.getCause() instanceof MessageRemovedException)
return null;
if (ex instanceof ConnectionException)
return null;
if (ex instanceof StoreClosedException ||
ex instanceof FolderClosedException || ex instanceof FolderClosedIOException)
return null;
if (ex instanceof IllegalStateException &&
("Not connected".equals(ex.getMessage()) ||
"This operation is not allowed on a closed folder".equals(ex.getMessage())))
return null;
}
StringBuilder sb = new StringBuilder();
if (BuildConfig.DEBUG)
sb.append(ex.toString());
else
sb.append(ex.getMessage() == null ? ex.getClass().getName() : ex.getMessage());
Throwable cause = ex.getCause();
while (cause != null) {
if (BuildConfig.DEBUG)
sb.append(separator).append(cause.toString());
else
sb.append(separator).append(cause.getMessage() == null ? cause.getClass().getName() : cause.getMessage());
cause = cause.getCause();
}
return sb.toString();
}
static void writeCrashLog(Context context, Throwable ex) {
File file = new File(context.getCacheDir(), "crash.log");
Log.w("Writing exception to " + file);
try (FileWriter out = new FileWriter(file, true)) {
out.write(BuildConfig.VERSION_NAME + " " + new Date() + "\r\n");
out.write(ex + "\r\n" + android.util.Log.getStackTraceString(ex) + "\r\n");
} catch (IOException e) {
Log.e(e);
}
}
static EntityMessage getDebugInfo(Context context, int title, Throwable ex, String log) throws IOException {
StringBuilder sb = new StringBuilder();
sb.append(context.getString(title)).append("\n\n\n\n");
sb.append(getAppInfo(context));
if (ex != null)
sb.append(ex.toString()).append("\n").append(android.util.Log.getStackTraceString(ex));
if (log != null)
sb.append(log);
String body = "" + TextUtils.htmlEncode(sb.toString()) + "
";
EntityMessage draft;
DB db = DB.getInstance(context);
try {
db.beginTransaction();
List identities = db.identity().getComposableIdentities(null);
if (identities == null || identities.size() == 0)
throw new IllegalArgumentException(context.getString(R.string.title_no_identities));
EntityIdentity identity = identities.get(0);
EntityFolder drafts = db.folder().getFolderByType(identity.account, EntityFolder.DRAFTS);
draft = new EntityMessage();
draft.account = drafts.account;
draft.folder = drafts.id;
draft.identity = identity.id;
draft.msgid = EntityMessage.generateMessageId();
draft.thread = draft.msgid;
draft.to = new Address[]{myAddress()};
draft.subject = context.getString(R.string.app_name) + " " + BuildConfig.VERSION_NAME + " debug info";
draft.received = new Date().getTime();
draft.seen = true;
draft.ui_seen = true;
draft.id = db.message().insertMessage(draft);
File file = draft.getFile(context);
Helper.writeText(file, body);
db.message().setMessageContent(draft.id,
true,
HtmlHelper.getLanguage(context, body),
false,
HtmlHelper.getPreview(body),
null);
attachSettings(context, draft.id, 1);
attachAccounts(context, draft.id, 2);
attachNetworkInfo(context, draft.id, 3);
attachLog(context, draft.id, 4);
attachOperations(context, draft.id, 5);
attachLogcat(context, draft.id, 6);
EntityOperation.queue(context, draft, EntityOperation.ADD);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
ServiceSynchronize.eval(context, "debuginfo");
return draft;
}
static void unexpectedError(FragmentManager manager, Throwable ex) {
Log.e(ex);
Bundle args = new Bundle();
args.putSerializable("ex", ex);
FragmentDialogUnexpected fragment = new FragmentDialogUnexpected();
fragment.setArguments(args);
fragment.show(manager, "error:unexpected");
}
public static class FragmentDialogUnexpected extends FragmentDialogBase {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
final Throwable ex = (Throwable) getArguments().getSerializable("ex");
return new AlertDialog.Builder(getContext())
.setTitle(R.string.title_unexpected_error)
.setMessage(Log.formatThrowable(ex, false))
.setPositiveButton(android.R.string.cancel, null)
.setNeutralButton(R.string.title_report, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Dialog will be dismissed
final Context context = getContext();
new SimpleTask() {
@Override
protected Long onExecute(Context context, Bundle args) throws Throwable {
return Log.getDebugInfo(context, R.string.title_crash_info_remark, ex, null).id;
}
@Override
protected void onExecuted(Bundle args, Long id) {
context.startActivity(new Intent(context, ActivityCompose.class)
.putExtra("action", "edit")
.putExtra("id", id));
}
@Override
protected void onException(Bundle args, Throwable ex) {
if (ex instanceof IllegalArgumentException)
ToastEx.makeText(context, ex.getMessage(), Toast.LENGTH_LONG).show();
else
ToastEx.makeText(context, ex.toString(), Toast.LENGTH_LONG).show();
}
}.execute(getContext(), getActivity(), new Bundle(), "error:unexpected");
}
})
.create();
}
}
private static StringBuilder getAppInfo(Context context) {
StringBuilder sb = new StringBuilder();
// Get version info
String installer = context.getPackageManager().getInstallerPackageName(BuildConfig.APPLICATION_ID);
sb.append(String.format("%s: %s/%s %s/%s%s%s%s\r\n",
context.getString(R.string.app_name),
BuildConfig.APPLICATION_ID,
installer,
BuildConfig.VERSION_NAME,
Helper.hasValidFingerprint(context) ? "1" : "3",
BuildConfig.PLAY_STORE_RELEASE ? "p" : "",
BuildConfig.DEBUG ? "d" : "",
ActivityBilling.isPro(context) ? "+" : ""));
sb.append(String.format("Android: %s (SDK %d)\r\n", Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
sb.append("\r\n");
// Get device info
sb.append(String.format("uid: %s\r\n", android.os.Process.myUid()));
sb.append(String.format("Brand: %s\r\n", Build.BRAND));
sb.append(String.format("Manufacturer: %s\r\n", Build.MANUFACTURER));
sb.append(String.format("Model: %s\r\n", Build.MODEL));
sb.append(String.format("Product: %s\r\n", Build.PRODUCT));
sb.append(String.format("Device: %s\r\n", Build.DEVICE));
sb.append(String.format("Host: %s\r\n", Build.HOST));
sb.append(String.format("Display: %s\r\n", Build.DISPLAY));
sb.append(String.format("Id: %s\r\n", Build.ID));
sb.append("\r\n");
sb.append(String.format("Processors: %d\r\n", Runtime.getRuntime().availableProcessors()));
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
sb.append(String.format("Memory class: %d\r\n", am.getMemoryClass()));
sb.append(String.format("Storage space: %s/%s\r\n",
Helper.humanReadableByteCount(Helper.getAvailableStorageSpace(), true),
Helper.humanReadableByteCount(Helper.getTotalStorageSpace(), true)));
Runtime rt = Runtime.getRuntime();
long hused = (rt.totalMemory() - rt.freeMemory()) / 1024L;
long hmax = rt.maxMemory() / 1024L;
long nheap = Debug.getNativeHeapAllocatedSize() / 1024L;
sb.append(String.format("Heap usage: %s/%s KiB native: %s KiB\r\n", hused, hmax, nheap));
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
float density = context.getResources().getDisplayMetrics().density;
sb.append(String.format("Density %f resolution: %.2f x %.2f dp %b\r\n",
density,
size.x / density, size.y / density,
context.getResources().getConfiguration().isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_NORMAL)));
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
boolean ignoring = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
ignoring = pm.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID);
sb.append(String.format("Battery optimizations: %b\r\n", !ignoring));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
UsageStatsManager usm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
int bucket = usm.getAppStandbyBucket();
sb.append(String.format("Standby bucket: %d\r\n", bucket));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
boolean saving = (cm.getRestrictBackgroundStatus() == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED);
sb.append(String.format("Data saving: %b\r\n", saving));
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean reporting = prefs.getBoolean("crash_reports", false);
if (reporting) {
String uuid = prefs.getString("uuid", null);
sb.append(String.format("UUID: %s\r\n", uuid == null ? "-" : uuid));
}
sb.append("\r\n");
sb.append(new Date(Helper.getInstallTime(context))).append("\r\n");
sb.append(new Date()).append("\r\n");
sb.append("\r\n");
return sb;
}
private static void attachSettings(Context context, long id, int sequence) throws IOException {
DB db = DB.getInstance(context);
EntityAttachment attachment = new EntityAttachment();
attachment.message = id;
attachment.sequence = sequence;
attachment.name = "settings.txt";
attachment.type = "text/plain";
attachment.disposition = Part.ATTACHMENT;
attachment.size = null;
attachment.progress = 0;
attachment.id = db.attachment().insertAttachment(attachment);
long size = 0;
File file = attachment.getFile(context);
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Map settings = prefs.getAll();
List keys = new ArrayList<>(settings.keySet());
Collections.sort(keys);
for (String key : keys)
size += write(os, key + "=" + settings.get(key) + "\r\n");
}
db.attachment().setDownloaded(attachment.id, size);
}
private static void attachAccounts(Context context, long id, int sequence) throws IOException {
DB db = DB.getInstance(context);
EntityAttachment attachment = new EntityAttachment();
attachment.message = id;
attachment.sequence = sequence;
attachment.name = "accounts.txt";
attachment.type = "text/plain";
attachment.disposition = Part.ATTACHMENT;
attachment.size = null;
attachment.progress = 0;
attachment.id = db.attachment().insertAttachment(attachment);
long size = 0;
File file = attachment.getFile(context);
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
List accounts = db.account().getAccounts();
size += write(os, "accounts=" + accounts.size() + "\r\n");
for (EntityAccount account : accounts)
try {
JSONObject jaccount = account.toJSON();
jaccount.put("state", account.state);
jaccount.put("warning", account.warning);
jaccount.put("error", account.error);
if (account.last_connected != null)
jaccount.put("last_connected", new Date(account.last_connected).toString());
jaccount.put("keep_alive_ok", account.keep_alive_ok);
jaccount.put("keep_alive_failed", account.keep_alive_failed);
jaccount.put("keep_alive_succeeded", account.keep_alive_succeeded);
jaccount.remove("user");
jaccount.remove("password");
size += write(os, "==========\r\n");
size += write(os, jaccount.toString(2) + "\r\n");
List folders = db.folder().getFolders(account.id, false, false);
if (folders.size() > 0)
Collections.sort(folders, folders.get(0).getComparator(context));
for (EntityFolder folder : folders) {
JSONObject jfolder = folder.toJSON();
jfolder.put("level", folder.level);
jfolder.put("total", folder.total);
jfolder.put("initialize", folder.initialize);
jfolder.put("subscribed", folder.subscribed);
jfolder.put("state", folder.state);
jfolder.put("sync_state", folder.sync_state);
jfolder.put("read_only", folder.read_only);
jfolder.put("selectable", folder.selectable);
jfolder.put("inferiors", folder.inferiors);
jfolder.put("error", folder.error);
if (folder.last_sync != null)
jfolder.put("last_sync", new Date(folder.last_sync).toString());
size += write(os, jfolder.toString(2) + "\r\n");
}
List identities = db.identity().getIdentities(account.id);
for (EntityIdentity identity : identities)
try {
JSONObject jidentity = identity.toJSON();
jidentity.remove("user");
jidentity.remove("password");
jidentity.remove("signature");
size += write(os, "----------\r\n");
size += write(os, jidentity.toString(2) + "\r\n");
} catch (JSONException ex) {
size += write(os, ex.toString() + "\r\n");
}
} catch (JSONException ex) {
size += write(os, ex.toString() + "\r\n");
}
}
db.attachment().setDownloaded(attachment.id, size);
}
private static void attachNetworkInfo(Context context, long id, int sequence) throws IOException {
DB db = DB.getInstance(context);
EntityAttachment attachment = new EntityAttachment();
attachment.message = id;
attachment.sequence = sequence;
attachment.name = "network.txt";
attachment.type = "text/plain";
attachment.disposition = Part.ATTACHMENT;
attachment.size = null;
attachment.progress = 0;
attachment.id = db.attachment().insertAttachment(attachment);
long size = 0;
File file = attachment.getFile(context);
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ani = cm.getActiveNetworkInfo();
if (ani != null)
size += write(os, ani.toString() + " metered=" + cm.isActiveNetworkMetered() + "\r\n\r\n");
Network active = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
active = cm.getActiveNetwork();
for (Network network : cm.getAllNetworks()) {
NetworkCapabilities caps = cm.getNetworkCapabilities(network);
size += write(os, (network.equals(active) ? "active=" : "network=") + network + " capabilities=" + caps + "\r\n\r\n");
}
size += write(os, "VPN active=" + ConnectionHelper.vpnActive(context) + "\r\n\r\n");
ConnectionHelper.NetworkState state = ConnectionHelper.getNetworkState(context);
size += write(os, "Connected=" + state.isConnected() + "\r\n");
size += write(os, "Suitable=" + state.isSuitable() + "\r\n");
size += write(os, "Unmetered=" + state.isUnmetered() + "\r\n");
size += write(os, "Roaming=" + state.isRoaming() + "\r\n");
size += write(os, "Type=" + state.getType() + "\r\n\r\n");
}
db.attachment().setDownloaded(attachment.id, size);
}
private static void attachLog(Context context, long id, int sequence) throws IOException {
DB db = DB.getInstance(context);
EntityAttachment attachment = new EntityAttachment();
attachment.message = id;
attachment.sequence = sequence;
attachment.name = "log.txt";
attachment.type = "text/plain";
attachment.disposition = Part.ATTACHMENT;
attachment.size = null;
attachment.progress = 0;
attachment.id = db.attachment().insertAttachment(attachment);
long size = 0;
File file = attachment.getFile(context);
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
long from = new Date().getTime() - 24 * 3600 * 1000L;
DateFormat TF = Helper.getTimeInstance(context);
for (EntityLog entry : db.log().getLogs(from))
size += write(os, String.format("%s %s\r\n", TF.format(entry.time), entry.data));
}
db.attachment().setDownloaded(attachment.id, size);
}
private static void attachOperations(Context context, long id, int sequence) throws IOException {
DB db = DB.getInstance(context);
EntityAttachment attachment = new EntityAttachment();
attachment.message = id;
attachment.sequence = sequence;
attachment.name = "operations.txt";
attachment.type = "text/plain";
attachment.disposition = Part.ATTACHMENT;
attachment.size = null;
attachment.progress = 0;
attachment.id = db.attachment().insertAttachment(attachment);
long size = 0;
File file = attachment.getFile(context);
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
DateFormat TF = Helper.getTimeInstance(context);
for (EntityOperation op : db.operation().getOperations())
size += write(os, String.format("%s %d %s/%d %s %s %s\r\n",
TF.format(op.created),
op.message == null ? -1 : op.message,
op.name,
op.tries,
op.args,
op.state,
op.error));
}
db.attachment().setDownloaded(attachment.id, size);
}
private static void attachLogcat(Context context, long id, int sequence) throws IOException {
DB db = DB.getInstance(context);
EntityAttachment attachment = new EntityAttachment();
attachment.message = id;
attachment.sequence = sequence;
attachment.name = "logcat.txt";
attachment.type = "text/plain";
attachment.disposition = Part.ATTACHMENT;
attachment.size = null;
attachment.progress = 0;
attachment.id = db.attachment().insertAttachment(attachment);
Process proc = null;
File file = attachment.getFile(context);
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
String[] cmd = new String[]{"logcat",
"-d",
"-v", "threadtime",
//"-t", "1000",
Log.TAG + ":I"};
proc = Runtime.getRuntime().exec(cmd);
long size = 0;
try (BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String line;
while ((line = br.readLine()) != null)
size += write(os, line + "\r\n");
}
db.attachment().setDownloaded(attachment.id, size);
} finally {
if (proc != null)
proc.destroy();
}
}
private static int write(OutputStream os, String text) throws IOException {
byte[] bytes = text.getBytes();
os.write(bytes);
return bytes.length;
}
private static long getFreeMem() {
Runtime rt = Runtime.getRuntime();
long used = (rt.totalMemory() - rt.freeMemory());
long max = rt.maxMemory();
return (max - used);
}
static int getFreeMemMb() {
return (int) (getFreeMem() / 1024L / 1024L);
}
static InternetAddress myAddress() throws UnsupportedEncodingException {
return new InternetAddress("marcel+fairemail@faircode.eu", "FairCode");
}
static boolean isSupportedDevice() {
if ("Amazon".equals(Build.BRAND) && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
/*
java.lang.IllegalArgumentException: Comparison method violates its general contract!
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:864)
at java.util.TimSort.mergeAt(TimSort.java:481)
at java.util.TimSort.mergeCollapse(TimSort.java:406)
at java.util.TimSort.sort(TimSort.java:210)
at java.util.TimSort.sort(TimSort.java:169)
at java.util.Arrays.sort(Arrays.java:2010)
at java.util.Collections.sort(Collections.java:1883)
at android.view.ViewGroup$ChildListForAccessibility.init(ViewGroup.java:7181)
at android.view.ViewGroup$ChildListForAccessibility.obtain(ViewGroup.java:7138)
at android.view.ViewGroup.dispatchPopulateAccessibilityEventInternal(ViewGroup.java:2734)
at android.view.View.dispatchPopulateAccessibilityEvent(View.java:5617)
at android.view.View.sendAccessibilityEventUncheckedInternal(View.java:5582)
at android.view.View.sendAccessibilityEventUnchecked(View.java:5566)
at android.view.View.sendAccessibilityEventInternal(View.java:5543)
at android.view.View.sendAccessibilityEvent(View.java:5512)
at android.view.View.onFocusChanged(View.java:5449)
at android.view.View.handleFocusGainInternal(View.java:5229)
at android.view.ViewGroup.handleFocusGainInternal(ViewGroup.java:651)
at android.view.View.requestFocusNoSearch(View.java:7950)
at android.view.View.requestFocus(View.java:7929)
at android.view.ViewGroup.requestFocus(ViewGroup.java:2612)
at android.view.ViewGroup.onRequestFocusInDescendants(ViewGroup.java:2657)
at android.view.ViewGroup.requestFocus(ViewGroup.java:2613)
at android.view.View.requestFocus(View.java:7896)
at android.view.View.requestFocus(View.java:7875)
at androidx.recyclerview.widget.RecyclerView.recoverFocusFromState(SourceFile:3788)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep3(SourceFile:4023)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(SourceFile:3652)
at androidx.recyclerview.widget.RecyclerView.consumePendingUpdateOperations(SourceFile:1877)
at androidx.recyclerview.widget.RecyclerView$w.run(SourceFile:5044)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:781)
at android.view.Choreographer.doCallbacks(Choreographer.java:592)
at android.view.Choreographer.doFrame(Choreographer.java:559)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:767)
*/
return false;
}
return true;
}
static boolean isXiaomi() {
return "Xiaomi".equalsIgnoreCase(Build.MANUFACTURER);
}
}