kotlin migration for network diagnostics
This commit is contained in:
parent
e4193631da
commit
06aa7dc5ad
|
@ -1,421 +0,0 @@
|
|||
package org.mariotaku.twidere.fragment;
|
||||
|
||||
import android.accounts.AccountManager;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.Selection;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlog;
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging;
|
||||
import org.mariotaku.restfu.RestAPIFactory;
|
||||
import org.mariotaku.restfu.RestFuUtils;
|
||||
import org.mariotaku.restfu.annotation.method.GET;
|
||||
import org.mariotaku.restfu.http.Endpoint;
|
||||
import org.mariotaku.restfu.http.HttpRequest;
|
||||
import org.mariotaku.restfu.http.HttpResponse;
|
||||
import org.mariotaku.restfu.http.RestHttpClient;
|
||||
import org.mariotaku.twidere.BuildConfig;
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.extension.model.CredentialsExtensionsKt;
|
||||
import org.mariotaku.twidere.model.AccountDetails;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.account.cred.OAuthCredentials;
|
||||
import org.mariotaku.twidere.model.util.AccountUtils;
|
||||
import org.mariotaku.twidere.util.DataStoreUtils;
|
||||
import org.mariotaku.twidere.util.MicroBlogAPIFactory;
|
||||
import org.mariotaku.twidere.util.dagger.DependencyHolder;
|
||||
import org.mariotaku.twidere.util.net.TwidereDns;
|
||||
import org.xbill.DNS.ResolverConfig;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import okhttp3.Dns;
|
||||
|
||||
import static org.mariotaku.twidere.Constants.DEFAULT_TWITTER_API_URL_FORMAT;
|
||||
import static org.mariotaku.twidere.Constants.KEY_BUILTIN_DNS_RESOLVER;
|
||||
import static org.mariotaku.twidere.Constants.KEY_DNS_SERVER;
|
||||
import static org.mariotaku.twidere.Constants.KEY_TCP_DNS_QUERY;
|
||||
|
||||
/**
|
||||
* Network diagnostics
|
||||
* Created by mariotaku on 16/2/9.
|
||||
*/
|
||||
public class NetworkDiagnosticsFragment extends BaseFragment {
|
||||
|
||||
private TextView mLogTextView;
|
||||
private Button mStartDiagnosticsButton;
|
||||
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
mStartDiagnosticsButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mLogTextView.setText(null);
|
||||
new DiagnosticsTask(NetworkDiagnosticsFragment.this).execute();
|
||||
}
|
||||
});
|
||||
mLogTextView.setMovementMethod(ScrollingMovementMethod.getInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mStartDiagnosticsButton = (Button) view.findViewById(R.id.start_diagnostics);
|
||||
mLogTextView = (TextView) view.findViewById(R.id.log_text);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_network_diagnostics, container, false);
|
||||
}
|
||||
|
||||
private void appendMessage(LogText message) {
|
||||
final Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
SpannableString coloredText = SpannableString.valueOf(message.message);
|
||||
switch (message.state) {
|
||||
case LogText.State.OK: {
|
||||
coloredText.setSpan(new ForegroundColorSpan(ContextCompat.getColor(activity,
|
||||
R.color.material_light_green)), 0, coloredText.length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
break;
|
||||
}
|
||||
case LogText.State.ERROR: {
|
||||
coloredText.setSpan(new ForegroundColorSpan(ContextCompat.getColor(activity,
|
||||
R.color.material_red)), 0, coloredText.length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
break;
|
||||
}
|
||||
case LogText.State.WARNING: {
|
||||
coloredText.setSpan(new ForegroundColorSpan(ContextCompat.getColor(activity,
|
||||
R.color.material_amber)), 0, coloredText.length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
break;
|
||||
}
|
||||
case LogText.State.DEFAULT:
|
||||
break;
|
||||
}
|
||||
mLogTextView.append(coloredText);
|
||||
Selection.setSelection(mLogTextView.getEditableText(), mLogTextView.length());
|
||||
}
|
||||
|
||||
static class DiagnosticsTask extends AsyncTask<Object, LogText, Object> {
|
||||
|
||||
private final WeakReference<NetworkDiagnosticsFragment> mFragmentRef;
|
||||
|
||||
private final Context mContext;
|
||||
private final ConnectivityManager mConnectivityManager;
|
||||
|
||||
DiagnosticsTask(NetworkDiagnosticsFragment fragment) {
|
||||
mFragmentRef = new WeakReference<>(fragment);
|
||||
mContext = fragment.getActivity().getApplicationContext();
|
||||
mConnectivityManager = (ConnectivityManager)
|
||||
mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doInBackground(Object... params) {
|
||||
publishProgress(new LogText("**** NOTICE ****", LogText.State.WARNING));
|
||||
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
|
||||
publishProgress(new LogText("Text below may have personal information, BE CAREFUL TO MAKE IT PUBLIC",
|
||||
LogText.State.WARNING));
|
||||
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
|
||||
DependencyHolder holder = DependencyHolder.Companion.get(mContext);
|
||||
final Dns dns = holder.getDns();
|
||||
final SharedPreferences prefs = holder.getPreferences();
|
||||
publishProgress(new LogText("Network preferences"), LogText.LINEBREAK);
|
||||
publishProgress(new LogText("using_resolver: " + prefs.getBoolean(KEY_BUILTIN_DNS_RESOLVER, false)), LogText.LINEBREAK);
|
||||
publishProgress(new LogText("tcp_dns_query: " + prefs.getBoolean(KEY_TCP_DNS_QUERY, false)), LogText.LINEBREAK);
|
||||
publishProgress(new LogText("dns_server: " + prefs.getString(KEY_DNS_SERVER, null)), LogText.LINEBREAK);
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
publishProgress(new LogText("System DNS servers"), LogText.LINEBREAK);
|
||||
|
||||
|
||||
final String[] servers = ResolverConfig.getCurrentConfig().servers();
|
||||
if (servers != null) {
|
||||
publishProgress(new LogText(Arrays.toString(servers)));
|
||||
} else {
|
||||
publishProgress(new LogText("null"));
|
||||
}
|
||||
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
|
||||
|
||||
for (UserKey accountKey : DataStoreUtils.INSTANCE.getAccountKeys(mContext)) {
|
||||
final AccountDetails details = AccountUtils.getAccountDetails(AccountManager.get(mContext), accountKey, true);
|
||||
final MicroBlog twitter = MicroBlogAPIFactory.getInstance(mContext, accountKey);
|
||||
if (details == null || twitter == null) continue;
|
||||
publishProgress(new LogText("Testing connection for account " + accountKey));
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
publishProgress(new LogText("api_url_format: " + details.credentials.api_url_format), LogText.LINEBREAK);
|
||||
if (details.credentials instanceof OAuthCredentials) {
|
||||
publishProgress(new LogText("same_oauth_signing_url: " + ((OAuthCredentials)
|
||||
details.credentials).same_oauth_signing_url), LogText.LINEBREAK);
|
||||
}
|
||||
publishProgress(new LogText("auth_type: " + details.credentials_type));
|
||||
|
||||
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
|
||||
|
||||
publishProgress(new LogText("Testing DNS functionality"));
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
final Endpoint endpoint = CredentialsExtensionsKt.getEndpoint(details.credentials, MicroBlog.class);
|
||||
final Uri uri = Uri.parse(endpoint.getUrl());
|
||||
final String host = uri.getHost();
|
||||
if (host != null) {
|
||||
testDns(dns, host);
|
||||
testNativeLookup(host);
|
||||
} else {
|
||||
publishProgress(new LogText("API URL format is invalid", LogText.State.ERROR));
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
}
|
||||
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
|
||||
publishProgress(new LogText("Testing Network connectivity"));
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
|
||||
final String baseUrl;
|
||||
if (details.credentials.api_url_format != null) {
|
||||
baseUrl = MicroBlogAPIFactory.getApiBaseUrl(details.credentials.api_url_format, "api");
|
||||
} else {
|
||||
baseUrl = MicroBlogAPIFactory.getApiBaseUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api");
|
||||
}
|
||||
RestHttpClient client = RestAPIFactory.getRestClient(twitter).getRestClient();
|
||||
HttpResponse response = null;
|
||||
try {
|
||||
publishProgress(new LogText("Connecting to " + baseUrl + "..."));
|
||||
HttpRequest.Builder builder = new HttpRequest.Builder();
|
||||
builder.method(GET.METHOD);
|
||||
builder.url(baseUrl);
|
||||
final long start = SystemClock.uptimeMillis();
|
||||
response = client.newCall(builder.build()).execute();
|
||||
publishProgress(new LogText(String.format(Locale.US, " OK (%d ms)",
|
||||
SystemClock.uptimeMillis() - start), LogText.State.OK));
|
||||
} catch (IOException e) {
|
||||
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.ERROR));
|
||||
}
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
try {
|
||||
if (response != null) {
|
||||
publishProgress(new LogText("Reading response..."));
|
||||
final long start = SystemClock.uptimeMillis();
|
||||
final CountOutputStream os = new CountOutputStream();
|
||||
response.getBody().writeTo(os);
|
||||
publishProgress(new LogText(String.format(Locale.US, " %d bytes (%d ms)",
|
||||
os.getTotal(), SystemClock.uptimeMillis() - start), LogText.State.OK));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.ERROR));
|
||||
} finally {
|
||||
RestFuUtils.closeSilently(response);
|
||||
}
|
||||
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
|
||||
|
||||
publishProgress(new LogText("Testing API functionality"));
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
testTwitter("verify_credentials", twitter, new TwitterTest() {
|
||||
@Override
|
||||
public void execute(MicroBlog twitter) throws MicroBlogException {
|
||||
twitter.verifyCredentials();
|
||||
}
|
||||
});
|
||||
testTwitter("get_home_timeline", twitter, new TwitterTest() {
|
||||
@Override
|
||||
public void execute(MicroBlog twitter) throws MicroBlogException {
|
||||
twitter.getHomeTimeline(new Paging().count(1));
|
||||
}
|
||||
});
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
}
|
||||
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
|
||||
publishProgress(new LogText("Testing common host names"));
|
||||
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
|
||||
|
||||
testDns(dns, "www.google.com");
|
||||
testNativeLookup("www.google.com");
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
testDns(dns, "github.com");
|
||||
testNativeLookup("github.com");
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
testDns(dns, "twitter.com");
|
||||
testNativeLookup("twitter.com");
|
||||
|
||||
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
|
||||
|
||||
publishProgress(new LogText("Build information: "));
|
||||
publishProgress(new LogText("version_code: " + BuildConfig.VERSION_CODE), LogText.LINEBREAK);
|
||||
publishProgress(new LogText("version_name: " + BuildConfig.VERSION_NAME), LogText.LINEBREAK);
|
||||
publishProgress(new LogText("flavor: " + BuildConfig.FLAVOR), LogText.LINEBREAK);
|
||||
publishProgress(new LogText("debug: " + BuildConfig.DEBUG), LogText.LINEBREAK);
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
publishProgress(new LogText("Basic system information: "));
|
||||
publishProgress(new LogText(String.valueOf(mContext.getResources().getConfiguration())));
|
||||
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
|
||||
publishProgress(new LogText("Active network info: "));
|
||||
publishProgress(new LogText(String.valueOf(mConnectivityManager.getActiveNetworkInfo())));
|
||||
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
|
||||
|
||||
publishProgress(new LogText("Done. You can send this log to me, and I'll contact you to solve related issue."));
|
||||
return null;
|
||||
}
|
||||
|
||||
private void testDns(Dns dns, final String host) {
|
||||
publishProgress(new LogText(String.format("Lookup %s...", host)));
|
||||
try {
|
||||
final long start = SystemClock.uptimeMillis();
|
||||
if (dns instanceof TwidereDns) {
|
||||
publishProgress(new LogText(String.valueOf(((TwidereDns) dns).lookupResolver(host))));
|
||||
} else {
|
||||
publishProgress(new LogText(String.valueOf(dns.lookup(host))));
|
||||
}
|
||||
publishProgress(new LogText(String.format(Locale.US, " OK (%d ms)",
|
||||
SystemClock.uptimeMillis() - start), LogText.State.OK));
|
||||
} catch (UnknownHostException e) {
|
||||
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.ERROR));
|
||||
}
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
}
|
||||
|
||||
private void testNativeLookup(final String host) {
|
||||
publishProgress(new LogText(String.format("Native lookup %s...", host)));
|
||||
try {
|
||||
final long start = SystemClock.uptimeMillis();
|
||||
publishProgress(new LogText(Arrays.toString(InetAddress.getAllByName(host))));
|
||||
publishProgress(new LogText(String.format(Locale.US, " OK (%d ms)",
|
||||
SystemClock.uptimeMillis() - start), LogText.State.OK));
|
||||
} catch (UnknownHostException e) {
|
||||
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.ERROR));
|
||||
}
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
}
|
||||
|
||||
private void testTwitter(String name, MicroBlog twitter, TwitterTest test) {
|
||||
publishProgress(new LogText(String.format("Testing %s...", name)));
|
||||
try {
|
||||
final long start = SystemClock.uptimeMillis();
|
||||
test.execute(twitter);
|
||||
publishProgress(new LogText(String.format(Locale.US, "OK (%d ms)",
|
||||
SystemClock.uptimeMillis() - start), LogText.State.OK));
|
||||
} catch (MicroBlogException e) {
|
||||
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.ERROR));
|
||||
}
|
||||
publishProgress(LogText.LINEBREAK);
|
||||
}
|
||||
|
||||
interface TwitterTest {
|
||||
void execute(MicroBlog twitter) throws MicroBlogException;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(LogText... values) {
|
||||
NetworkDiagnosticsFragment fragment = mFragmentRef.get();
|
||||
if (fragment == null) return;
|
||||
for (LogText value : values) {
|
||||
fragment.appendMessage(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
NetworkDiagnosticsFragment fragment = mFragmentRef.get();
|
||||
if (fragment == null) return;
|
||||
fragment.diagStart();
|
||||
super.onPreExecute();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Object o) {
|
||||
NetworkDiagnosticsFragment fragment = mFragmentRef.get();
|
||||
if (fragment == null) return;
|
||||
fragment.logReady();
|
||||
super.onPostExecute(o);
|
||||
}
|
||||
}
|
||||
|
||||
private void diagStart() {
|
||||
mStartDiagnosticsButton.setText(R.string.message_please_wait);
|
||||
mStartDiagnosticsButton.setEnabled(false);
|
||||
}
|
||||
|
||||
private void logReady() {
|
||||
mStartDiagnosticsButton.setText(R.string.action_send);
|
||||
mStartDiagnosticsButton.setEnabled(true);
|
||||
mStartDiagnosticsButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Twidere Network Diagnostics");
|
||||
intent.putExtra(android.content.Intent.EXTRA_TEXT, mLogTextView.getText());
|
||||
startActivity(Intent.createChooser(intent, getString(R.string.action_send)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static class LogText {
|
||||
static final LogText LINEBREAK = new LogText("\n");
|
||||
String message;
|
||||
@State
|
||||
int state = State.DEFAULT;
|
||||
|
||||
LogText(String message, @State int state) {
|
||||
this.message = message;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
LogText(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@IntDef({State.DEFAULT, State.OK, State.ERROR, State.WARNING})
|
||||
@interface State {
|
||||
int DEFAULT = 0;
|
||||
int OK = 1;
|
||||
int ERROR = 2;
|
||||
int WARNING = 3;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CountOutputStream extends OutputStream {
|
||||
private long total;
|
||||
|
||||
public long getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int oneByte) throws IOException {
|
||||
total++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,348 @@
|
|||
package org.mariotaku.twidere.fragment
|
||||
|
||||
import android.accounts.AccountManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.text.Selection
|
||||
import android.text.SpannableString
|
||||
import android.text.Spanned
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import kotlinx.android.synthetic.main.fragment_network_diagnostics.*
|
||||
import okhttp3.Dns
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.mastodon.Mastodon
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging
|
||||
import org.mariotaku.restfu.RestFuUtils
|
||||
import org.mariotaku.restfu.annotation.method.GET
|
||||
import org.mariotaku.restfu.http.HttpRequest
|
||||
import org.mariotaku.restfu.http.HttpResponse
|
||||
import org.mariotaku.twidere.BuildConfig
|
||||
import org.mariotaku.twidere.Constants.DEFAULT_TWITTER_API_URL_FORMAT
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.*
|
||||
import org.mariotaku.twidere.extension.model.getEndpoint
|
||||
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
|
||||
import org.mariotaku.twidere.model.account.cred.OAuthCredentials
|
||||
import org.mariotaku.twidere.model.util.AccountUtils
|
||||
import org.mariotaku.twidere.util.DataStoreUtils
|
||||
import org.mariotaku.twidere.util.MicroBlogAPIFactory
|
||||
import org.mariotaku.twidere.util.dagger.DependencyHolder
|
||||
import org.mariotaku.twidere.util.net.TwidereDns
|
||||
import org.xbill.DNS.ResolverConfig
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
import java.lang.ref.WeakReference
|
||||
import java.net.InetAddress
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Network diagnostics
|
||||
* Created by mariotaku on 16/2/9.
|
||||
*/
|
||||
class NetworkDiagnosticsFragment : BaseFragment() {
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
startDiagnostics.setOnClickListener {
|
||||
logText.text = null
|
||||
DiagnosticsTask(this@NetworkDiagnosticsFragment).execute()
|
||||
}
|
||||
logText.movementMethod = ScrollingMovementMethod.getInstance()
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_network_diagnostics, container, false)
|
||||
}
|
||||
|
||||
private fun appendMessage(message: LogText) {
|
||||
val activity = activity ?: return
|
||||
val coloredText = SpannableString.valueOf(message.message)
|
||||
when (message.state) {
|
||||
LogText.State.OK -> {
|
||||
coloredText.setSpan(ForegroundColorSpan(ContextCompat.getColor(activity,
|
||||
R.color.material_light_green)), 0, coloredText.length,
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
LogText.State.ERROR -> {
|
||||
coloredText.setSpan(ForegroundColorSpan(ContextCompat.getColor(activity,
|
||||
R.color.material_red)), 0, coloredText.length,
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
LogText.State.WARNING -> {
|
||||
coloredText.setSpan(ForegroundColorSpan(ContextCompat.getColor(activity,
|
||||
R.color.material_amber)), 0, coloredText.length,
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
LogText.State.DEFAULT -> {
|
||||
}
|
||||
}
|
||||
logText.append(coloredText)
|
||||
Selection.setSelection(logText.editableText, logText.length())
|
||||
}
|
||||
|
||||
internal class DiagnosticsTask(fragment: NetworkDiagnosticsFragment) : AsyncTask<Any, LogText, Unit>() {
|
||||
|
||||
private val fragmentRef = WeakReference(fragment)
|
||||
|
||||
private val context = fragment.activity.applicationContext
|
||||
private val connectivityManager: ConnectivityManager
|
||||
|
||||
init {
|
||||
connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
}
|
||||
|
||||
override fun doInBackground(vararg params: Any) {
|
||||
logPrintln("**** NOTICE ****", LogText.State.WARNING)
|
||||
logPrintln()
|
||||
logPrintln("Text below may have personal information, BE CAREFUL TO MAKE IT PUBLIC",
|
||||
LogText.State.WARNING)
|
||||
logPrintln()
|
||||
val holder = DependencyHolder.get(context)
|
||||
val dns = holder.dns
|
||||
val prefs = holder.preferences
|
||||
logPrintln(("Network preferences"))
|
||||
logPrintln(("using_resolver: ${prefs.getBoolean(KEY_BUILTIN_DNS_RESOLVER, false)}"))
|
||||
logPrintln(("tcp_dns_query: ${prefs.getBoolean(KEY_TCP_DNS_QUERY, false)}"))
|
||||
logPrintln(("dns_server: ${prefs.getString(KEY_DNS_SERVER, null)}"))
|
||||
logPrintln()
|
||||
logPrintln(("System DNS servers"))
|
||||
|
||||
|
||||
val servers = ResolverConfig.getCurrentConfig().servers()
|
||||
if (servers != null) {
|
||||
logPrintln(Arrays.toString(servers))
|
||||
} else {
|
||||
logPrintln("null")
|
||||
}
|
||||
logPrintln()
|
||||
|
||||
for (accountKey in DataStoreUtils.getAccountKeys(context)) {
|
||||
val details = AccountUtils.getAccountDetails(AccountManager.get(context),
|
||||
accountKey, true) ?: continue
|
||||
logPrintln(("Testing connection for account $accountKey"))
|
||||
logPrintln()
|
||||
logPrintln(("api_url_format: ${details.credentials.api_url_format}"))
|
||||
(details.credentials as? OAuthCredentials)?.let { creds ->
|
||||
logPrintln(("same_oauth_signing_url: ${creds.same_oauth_signing_url}"))
|
||||
}
|
||||
logPrintln(("auth_type: " + details.credentials_type))
|
||||
|
||||
logPrintln()
|
||||
|
||||
logPrintln(("Testing DNS functionality"))
|
||||
logPrintln()
|
||||
val endpoint = details.credentials.getEndpoint(MicroBlog::class.java)
|
||||
val uri = Uri.parse(endpoint.url)
|
||||
val host = uri.host
|
||||
if (host != null) {
|
||||
testDns(dns, host)
|
||||
testNativeLookup(host)
|
||||
} else {
|
||||
logPrintln("API URL format is invalid", LogText.State.ERROR)
|
||||
logPrintln()
|
||||
}
|
||||
|
||||
logPrintln()
|
||||
|
||||
logPrintln(("Testing Network connectivity"))
|
||||
logPrintln()
|
||||
|
||||
val baseUrl: String
|
||||
if (details.credentials.api_url_format != null) {
|
||||
baseUrl = MicroBlogAPIFactory.getApiBaseUrl(details.credentials.api_url_format, "api")
|
||||
} else {
|
||||
baseUrl = MicroBlogAPIFactory.getApiBaseUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api")
|
||||
}
|
||||
val client = DependencyHolder.get(context).restHttpClient
|
||||
var response: HttpResponse? = null
|
||||
try {
|
||||
logPrint("Connecting to $baseUrl...")
|
||||
val builder = HttpRequest.Builder()
|
||||
builder.method(GET.METHOD)
|
||||
builder.url(baseUrl)
|
||||
val start = SystemClock.uptimeMillis()
|
||||
response = client.newCall(builder.build()).execute()
|
||||
logPrint(" OK (${SystemClock.uptimeMillis() - start} ms)")
|
||||
} catch (e: IOException) {
|
||||
logPrint("ERROR: ${e.message}", LogText.State.ERROR)
|
||||
}
|
||||
|
||||
logPrintln()
|
||||
try {
|
||||
if (response != null) {
|
||||
logPrintln("Reading response...")
|
||||
val start = SystemClock.uptimeMillis()
|
||||
val os = CountOutputStream()
|
||||
response.body.writeTo(os)
|
||||
logPrintln(" ${os.total} bytes (${SystemClock.uptimeMillis() - start} ms)", LogText.State.OK)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
logPrintln("ERROR: ${e.message}", LogText.State.ERROR)
|
||||
} finally {
|
||||
RestFuUtils.closeSilently(response)
|
||||
}
|
||||
logPrintln()
|
||||
|
||||
logPrintln(("Testing API functionality"))
|
||||
logPrintln()
|
||||
when (details.type) {
|
||||
AccountType.MASTODON -> {
|
||||
val mastodon = details.newMicroBlogInstance(context, Mastodon::class.java)
|
||||
testAPICall("verify_credentials", mastodon) {
|
||||
verifyCredentials()
|
||||
}
|
||||
testAPICall("get_home_timeline", mastodon) {
|
||||
getHomeTimeline(Paging().count(1))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
val microBlog = details.newMicroBlogInstance(context, MicroBlog::class.java)
|
||||
testAPICall("verify_credentials", microBlog) {
|
||||
verifyCredentials()
|
||||
}
|
||||
testAPICall("get_home_timeline", microBlog) {
|
||||
getHomeTimeline(Paging().count(1))
|
||||
}
|
||||
}
|
||||
}
|
||||
logPrintln()
|
||||
}
|
||||
|
||||
logPrintln()
|
||||
|
||||
logPrintln(("Testing common host names"))
|
||||
logPrintln()
|
||||
|
||||
testDns(dns, "www.google.com")
|
||||
testNativeLookup("www.google.com")
|
||||
logPrintln()
|
||||
testDns(dns, "github.com")
|
||||
testNativeLookup("github.com")
|
||||
logPrintln()
|
||||
testDns(dns, "twitter.com")
|
||||
testNativeLookup("twitter.com")
|
||||
|
||||
logPrintln()
|
||||
|
||||
logPrintln("Build information: ")
|
||||
logPrintln("version_code: ${BuildConfig.VERSION_CODE}")
|
||||
logPrintln("version_name: ${BuildConfig.VERSION_NAME}")
|
||||
logPrintln("flavor: ${BuildConfig.FLAVOR}")
|
||||
logPrintln("debug: ${BuildConfig.DEBUG}")
|
||||
logPrintln()
|
||||
logPrintln(("Basic system information: "))
|
||||
logPrintln(context.resources.configuration.toString())
|
||||
logPrintln()
|
||||
logPrintln(("Active network info: "))
|
||||
logPrintln((connectivityManager.activeNetworkInfo.toString()))
|
||||
}
|
||||
|
||||
override fun onProgressUpdate(vararg values: LogText) {
|
||||
val fragment = fragmentRef.get() ?: return
|
||||
for (value in values) {
|
||||
fragment.appendMessage(value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPreExecute() {
|
||||
val fragment = fragmentRef.get() ?: return
|
||||
fragment.diagStart()
|
||||
super.onPreExecute()
|
||||
}
|
||||
|
||||
override fun onPostExecute(u: Unit) {
|
||||
val fragment = fragmentRef.get() ?: return
|
||||
logPrintln()
|
||||
logPrintln(("Done. You can send this log to me, and I'll contact you to solve related issue."))
|
||||
fragment.logReady()
|
||||
}
|
||||
|
||||
private fun testDns(dns: Dns, host: String) {
|
||||
testCall("builtin lookup $host") {
|
||||
if (dns is TwidereDns) {
|
||||
logPrint((dns.lookupResolver(host).toString()))
|
||||
} else {
|
||||
logPrint((dns.lookup(host).toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun testNativeLookup(host: String) {
|
||||
testCall("native lookup $host") {
|
||||
logPrint(Arrays.toString(InetAddress.getAllByName(host)))
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> testAPICall(name: String, api: T, test: T.() -> Unit) {
|
||||
testCall(name) { test(api) }
|
||||
}
|
||||
|
||||
private inline fun testCall(name: String, test: () -> Unit) {
|
||||
logPrint("Testing $name...")
|
||||
try {
|
||||
val start = SystemClock.uptimeMillis()
|
||||
test()
|
||||
logPrint("OK (${SystemClock.uptimeMillis() - start} ms)", LogText.State.OK)
|
||||
} catch (e: Exception) {
|
||||
logPrint("ERROR: ${e.message}", LogText.State.ERROR)
|
||||
}
|
||||
|
||||
logPrintln()
|
||||
}
|
||||
|
||||
private fun logPrint(text: CharSequence, state: LogText.State = LogText.State.DEFAULT) {
|
||||
publishProgress(LogText(text, state))
|
||||
}
|
||||
|
||||
private fun logPrintln(text: CharSequence = "", state: LogText.State = LogText.State.DEFAULT) {
|
||||
logPrint("$text\n", state)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun diagStart() {
|
||||
startDiagnostics.setText(R.string.message_please_wait)
|
||||
startDiagnostics.isEnabled = false
|
||||
}
|
||||
|
||||
private fun logReady() {
|
||||
startDiagnostics.setText(R.string.action_send)
|
||||
startDiagnostics.isEnabled = true
|
||||
startDiagnostics.setOnClickListener {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.type = "text/plain"
|
||||
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Twidere Network Diagnostics")
|
||||
intent.putExtra(android.content.Intent.EXTRA_TEXT, logText.text)
|
||||
startActivity(Intent.createChooser(intent, getString(R.string.action_send)))
|
||||
}
|
||||
}
|
||||
|
||||
internal data class LogText(val message: CharSequence, var state: State = State.DEFAULT) {
|
||||
|
||||
internal enum class State {
|
||||
DEFAULT, OK, ERROR, WARNING
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class CountOutputStream : OutputStream() {
|
||||
var total: Long = 0
|
||||
private set
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun write(oneByte: Int) {
|
||||
total++
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<org.mariotaku.twidere.view.FixedTextView
|
||||
android:id="@+id/log_text"
|
||||
android:id="@+id/logText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
|
@ -18,7 +18,7 @@
|
|||
android:typeface="monospace"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/start_diagnostics"
|
||||
android:id="@+id/startDiagnostics"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
|
|
Loading…
Reference in New Issue