/* * Copyright 2015 Hippo Seven * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hippo.nimingban.ui; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Dialog; import android.app.Fragment; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.SystemClock; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceFragment; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.v7.app.AlertDialog; import android.text.TextUtils; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.EditText; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.PopupWindow; import android.widget.TextView; import android.widget.Toast; import com.alibaba.fastjson.JSON; import com.hippo.nimingban.Constants; import com.hippo.nimingban.NMBAppConfig; import com.hippo.nimingban.NMBApplication; import com.hippo.nimingban.R; import com.hippo.nimingban.client.data.ACSite; import com.hippo.nimingban.network.SimpleCookieStore; import com.hippo.nimingban.network.TransportableHttpCookie; import com.hippo.nimingban.service.DaDiaoService; import com.hippo.nimingban.util.CountDownTimerEx; import com.hippo.nimingban.util.LinkMovementMethod2; import com.hippo.nimingban.util.OpenUrlHelper; import com.hippo.nimingban.util.ReadableTime; import com.hippo.nimingban.util.Settings; import com.hippo.nimingban.widget.FontTextView; import com.hippo.nimingban.widget.PopupTextView; import com.hippo.preference.FixedSwitchPreference; import com.hippo.preference.IconListPreference; import com.hippo.text.Html; import com.hippo.unifile.UniFile; import com.hippo.util.ActivityHelper; import com.hippo.util.DrawableManager; import com.hippo.util.LogCat; import com.hippo.widget.Slider; import com.hippo.yorozuya.IOUtils; import com.hippo.yorozuya.LayoutUtils; import com.hippo.yorozuya.MathUtils; import com.hippo.yorozuya.Messenger; import com.hippo.yorozuya.NumberUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.net.HttpCookie; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class SettingsActivity extends AbsPreferenceActivity { private static final int REQUEST_CODE_FRAGMENT = 0; private static final String[] ENTRY_FRAGMENTS = { DisplayFragment.class.getName(), ConfigFragment.class.getName(), InfoFragment.class.getName() }; @Override protected int getLightThemeResId() { return R.style.AppTheme; } @Override protected int getDarkThemeResId() { return R.style.AppTheme_Dark; } private class FakeLayoutInflater extends LayoutInflater { private LayoutInflater mInflater; protected FakeLayoutInflater(LayoutInflater inflater) { super(null); mInflater = inflater; } @Override public LayoutInflater cloneInContext(Context newContext) { return null; } @Override public View inflate(int resource, ViewGroup root, boolean attachToRoot) { return mInflater.inflate(R.layout.item_preference_header, root, attachToRoot); } } private void replaceHeaderLayoutResId() { try { ListAdapter adapter = getListAdapter(); Class headerAdapterClazz = Class.forName("android.preference.PreferenceActivity$HeaderAdapter"); if (!headerAdapterClazz.isInstance(adapter)) { return; } boolean ok = false; try { Field field = headerAdapterClazz.getDeclaredField("mLayoutResId"); field.setAccessible(true); field.setInt(adapter, R.layout.item_preference_header); ok = true; } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } if (!ok) { try { Field field = headerAdapterClazz.getDeclaredField("mInflater"); field.setAccessible(true); field.set(adapter, new FakeLayoutInflater((LayoutInflater) field.get(adapter))); ok = true; } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (ClassCastException e) { e.printStackTrace(); } } if (ok) { getListView().setDivider(getResources().getDrawable(R.drawable.transparent)); getListView().setDividerHeight(0); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setActionBarUpIndicator(DrawableManager.getDrawable(this, R.drawable.v_arrow_left_dark_x24)); replaceHeaderLayoutResId(); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: finish(); return true; default: return super.onOptionsItemSelected(item); } } @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.settings_headers, target); } @Override public void startWithFragment(String fragmentName, Bundle args, Fragment resultTo, int resultRequestCode, @StringRes int titleRes, @StringRes int shortTitleRes) { Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes); if (resultTo == null) { startActivityForResult(intent, REQUEST_CODE_FRAGMENT); } else { resultTo.startActivityForResult(intent, resultRequestCode); } } @Override protected boolean isValidFragment(String fragmentName) { for (String fragment : ENTRY_FRAGMENTS) { if (fragment.equals(fragmentName)) { return true; } } return false; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_FRAGMENT) { setResult(resultCode); } else { super.onActivityResult(requestCode, resultCode, data); } } // A bug for SwitchPreference in pre-L // http://stackoverflow.com/questions/15632215/preference-items-being-automatically-re-set public static class DisplayFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener { private static final String KEY_TEXT_FORMAT = "text_format"; private FixedSwitchPreference mPrettyTime; private Preference mTextFormat; private Preference mDynamicComments; private ListPreference mImageLoadingStrategy; private FixedSwitchPreference mImageLoadingStrategy2; private FixedSwitchPreference mFastScroller; private FixedSwitchPreference mColorStatusBar; private FixedSwitchPreference mFixEmojiDisplay; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.display_settings); Resources resources = getResources(); mPrettyTime = (FixedSwitchPreference) findPreference(Settings.KEY_PRETTY_TIME); mTextFormat = findPreference(KEY_TEXT_FORMAT); mDynamicComments = findPreference(Settings.KEY_DYNAMIC_COMMENTS); mImageLoadingStrategy = (ListPreference) findPreference(Settings.KEY_IMAGE_LOADING_STRATEGY); mImageLoadingStrategy2 = (FixedSwitchPreference) findPreference(Settings.KEY_IMAGE_LOADING_STRATEGY_2); mFastScroller = (FixedSwitchPreference) findPreference(Settings.KEY_FAST_SCROLLER); mColorStatusBar = (FixedSwitchPreference) findPreference(Settings.KEY_COLOR_STATUS_BAR); mFixEmojiDisplay = (FixedSwitchPreference) findPreference(Settings.KEY_FIX_EMOJI_DISPLAY); mPrettyTime.setOnPreferenceChangeListener(this); mDynamicComments.setOnPreferenceChangeListener(this); mImageLoadingStrategy.setOnPreferenceChangeListener(this); mImageLoadingStrategy2.setOnPreferenceChangeListener(this); mFastScroller.setOnPreferenceChangeListener(this); mColorStatusBar.setOnPreferenceChangeListener(this); mFixEmojiDisplay.setOnPreferenceChangeListener(this); mTextFormat.setOnPreferenceClickListener(this); long time = System.currentTimeMillis() - 3 * ReadableTime.HOUR_MILLIS; String plain = ReadableTime.getPlainTime(time); String timeAgo = ReadableTime.getTimeAgo(time); mPrettyTime.setSummaryOn(resources.getString(R.string.main_pretty_time_summary, timeAgo, plain)); mPrettyTime.setSummaryOff(resources.getString(R.string.main_pretty_time_summary, plain, timeAgo)); updateTextFormatSummary(); if (Build.VERSION.SDK_INT != Build.VERSION_CODES.KITKAT) { mColorStatusBar.setEnabled(false); mColorStatusBar.setSummaryOn(R.string.main_color_status_bar_summary_disable); mColorStatusBar.setSummaryOff(R.string.main_color_status_bar_summary_disable); } } private void updateTextFormatSummary() { mTextFormat.setSummary(getResources().getString( R.string.main_text_format_summary, Settings.getFontSize(), Settings.getLineSpacing())); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { String key = preference.getKey(); if (Settings.KEY_PRETTY_TIME.equals(key)) { getActivity().setResult(RESULT_OK); return true; } else if (Settings.KEY_DYNAMIC_COMMENTS.equals(key)) { getActivity().setResult(RESULT_OK); return true; } else if (Settings.KEY_IMAGE_LOADING_STRATEGY.equals(key)) { getActivity().setResult(RESULT_OK); return true; } else if (Settings.KEY_IMAGE_LOADING_STRATEGY_2.equals(key)) { getActivity().setResult(RESULT_OK); return true; } else if (Settings.KEY_FAST_SCROLLER.equals(key)) { Messenger.getInstance().notify(Constants.MESSENGER_ID_FAST_SCROLLER, newValue); return true; } else if (Settings.KEY_COLOR_STATUS_BAR.equals(key)) { Messenger.getInstance().notify(Constants.MESSENGER_ID_CHANGE_THEME, Settings.getDarkTheme()); } else if (Settings.KEY_FIX_EMOJI_DISPLAY.equals(key)) { getActivity().setResult(RESULT_OK); return true; } return true; } private class TextFormatDialogHelper implements Slider.OnSetProgressListener, DialogInterface.OnClickListener { public View mView; public FontTextView mPreview; public Slider mFontSize; public Slider mLineSpacing; @SuppressLint("InflateParams") public TextFormatDialogHelper() { mView = getActivity().getLayoutInflater().inflate(R.layout.dialog_text_format, null); mPreview = (FontTextView) mView.findViewById(R.id.preview); mFontSize = (Slider) mView.findViewById(R.id.font_size); mLineSpacing = (Slider) mView.findViewById(R.id.line_spacing); int fontSize = Settings.getFontSize(); int lineSpacing = Settings.getLineSpacing(); mPreview.setTextSize(fontSize); mPreview.setLineSpacing(LayoutUtils.dp2pix(getActivity(), lineSpacing), 1.0f); if (Settings.getFixEmojiDisplay()) { mPreview.useCustomTypeface(); } else { mPreview.useOriginalTypeface(); } mFontSize.setProgress(fontSize); mLineSpacing.setProgress(lineSpacing); mFontSize.setOnSetProgressListener(this); mLineSpacing.setOnSetProgressListener(this); } public View getView() { return mView; } @Override public void onSetProgress(Slider slider, int newProgress, int oldProgress, boolean byUser, boolean confirm) { if (slider == mFontSize && byUser) { mPreview.setTextSize(newProgress); } else if (slider == mLineSpacing && byUser) { mPreview.setLineSpacing(LayoutUtils.dp2pix(getActivity(), newProgress), 1.0f); } } @Override public void onFingerDown() {} @Override public void onFingerUp() {} @Override public void onClick(@NonNull DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { Settings.putFontSize(mFontSize.getProgress()); Settings.putLineSpacing(mLineSpacing.getProgress()); getActivity().setResult(RESULT_OK); updateTextFormatSummary(); } } } @Override public boolean onPreferenceClick(Preference preference) { String key = preference.getKey(); if (KEY_TEXT_FORMAT.equals(key)) { TextFormatDialogHelper helper = new TextFormatDialogHelper(); new AlertDialog.Builder(getActivity()) .setTitle(R.string.text_format) .setView(helper.getView()) .setPositiveButton(android.R.string.ok, helper) .show(); } return true; } } public static class ConfigFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener { public static final int REQUEST_CODE_PICK_IMAGE_DIR = 0; public static final int REQUEST_CODE_PICK_IMAGE_DIR_L = 1; private static final String KEY_AC_COOKIES = "ac_cookies"; private static final String KEY_SAVE_COOKIES = "save_cookies"; private static final String KEY_RESTORE_COOKIES = "restore_cookies"; private static final String KEY_APP_ICON = "app_icon"; private static final String KEY_ABOUT_ANALYSIS = "about_analysis"; private Preference mACCookies; private Preference mSaveCookies; private Preference mRestoreCookies; private Preference mFeedId; private Preference mImageSaveLocation; private Preference mChaosLevel; private IconListPreference mAppIcon; private Preference mAboutAnalysis; private long mMaxAgeDiff = 0; private TimingLife mTimingLife; private final long[] mHits = new long[8]; private PopupWindow mPopupWindow; private PopupTextView mPopupTextView; private int[] mLocation = new int[2]; private int mClick = 0; private int mXuMing; private String mXuMingStr; @Override public void onDestroy() { super.onDestroy(); // Update cookie max age if (mMaxAgeDiff != 0) { ACSite acSite = ACSite.getInstance(); long maxAge = acSite.getCookieMaxAge(getActivity()); acSite.setCookieMaxAge(getActivity(), maxAge + mMaxAgeDiff / 1000); } stopTimingLife(); if (mPopupWindow.isShowing()) { mPopupWindow.dismiss(); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.config_settings); mACCookies = findPreference(KEY_AC_COOKIES); mSaveCookies = findPreference(KEY_SAVE_COOKIES); mRestoreCookies = findPreference(KEY_RESTORE_COOKIES); mFeedId = findPreference(Settings.KEY_FEED_ID); mImageSaveLocation = findPreference(Settings.KEY_IMAGE_SAVE_LOACTION); mChaosLevel = findPreference(Settings.KEY_CHAOS_LEVEL); mAppIcon = (IconListPreference) findPreference(KEY_APP_ICON); mAboutAnalysis = findPreference(KEY_ABOUT_ANALYSIS); mACCookies.setOnPreferenceClickListener(this); mSaveCookies.setOnPreferenceClickListener(this); mRestoreCookies.setOnPreferenceClickListener(this); mFeedId.setOnPreferenceClickListener(this); mImageSaveLocation.setOnPreferenceClickListener(this); mAboutAnalysis.setOnPreferenceClickListener(this); mChaosLevel.setOnPreferenceChangeListener(this); mAppIcon.setOnPreferenceChangeListener(this); long maxAge = ACSite.getInstance().getCookieMaxAge(getActivity()); setACCookiesSummary(maxAge); updateFeedIdSummary(); updateImageSaveLocation(); mPopupTextView = new PopupTextView(getActivity()); mPopupWindow = new PopupWindow(mPopupTextView); mPopupWindow.setOutsideTouchable(false); mPopupWindow.setTouchable(false); mPopupWindow.setFocusable(false); mPopupWindow.setAnimationStyle(0); // Popup window ((SettingsActivity) getActivity()).getListView() .getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { ((SettingsActivity) getActivity()).getListView().getViewTreeObserver().removeGlobalOnLayoutListener(this); ensurePopupWindow(); } }); } private void startTimingLife(long millisInFuture) { if (mTimingLife == null) { mMaxAgeDiff = 0; mTimingLife = new TimingLife(millisInFuture, 1000); mTimingLife.start(); } } private void stopTimingLife() { if (mTimingLife != null) { mMaxAgeDiff = 0; mTimingLife.cancel(); mTimingLife = null; } } private void setACCookiesSummary(long maxAge) { Resources resources = getActivity().getResources(); if (maxAge == -1) { mACCookies.setSummary(resources.getString(R.string.main_ac_cookies_summary_forever)); stopTimingLife(); } else if (maxAge == -2) { mACCookies.setSummary(resources.getString(R.string.main_ac_cookies_summary_no)); stopTimingLife(); } else { long time = maxAge * 1000; mACCookies.setSummary(resources.getString(R.string.main_ac_cookies_summary_valid, ReadableTime.getTimeInterval(time))); startTimingLife(time); } } private void openDirPicker() { UniFile uniFile = Settings.getImageSaveLocation(); Intent intent = new Intent(getActivity(), DirPickerActivity.class); if (uniFile != null) { intent.putExtra(DirPickerActivity.KEY_FILE_URI, uniFile.getUri()); } startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE_DIR); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void openDirPickerL() { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); try { startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE_DIR_L); } catch (ActivityNotFoundException e) { Toast.makeText(getActivity(), R.string.em_cant_find_activity, Toast.LENGTH_SHORT).show(); } } private void showDirPickerDialogKK() { new AlertDialog.Builder(getActivity()).setMessage(R.string.pick_dir_kk) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { openDirPicker(); } }).show(); } private void showDirPickerDialogL() { DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case DialogInterface.BUTTON_POSITIVE: openDirPicker(); break; case DialogInterface.BUTTON_NEUTRAL: openDirPickerL(); break; } } }; new AlertDialog.Builder(getActivity()).setMessage(R.string.pick_dir_l) .setPositiveButton(android.R.string.ok, listener) .setNeutralButton(R.string.document, listener) .show(); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { String key = preference.getKey(); if (Settings.KEY_CHAOS_LEVEL.equals(key)) { getActivity().setResult(ListActivity.RESULT_CODE_REFRESH); return true; } else if (KEY_APP_ICON.equals(key)) { int index = NumberUtils.parseIntSafely((String) newValue, 0); if (index < 0 || index >= Settings.ICON_ACTIVITY_ARRAY.length) { return false; } PackageManager p = getActivity().getPackageManager(); for (int i = 0; i < Settings.ICON_ACTIVITY_ARRAY.length; i++) { ComponentName c = new ComponentName(getActivity(), Settings.ICON_ACTIVITY_ARRAY[i]); p.setComponentEnabledSetting(c, i == index ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); } return true; } return false; } private class SaveCookieTask extends AsyncTask<Void, Void, String> { private final Context mContext; public SaveCookieTask(Context context) { mContext = context.getApplicationContext(); } @Override protected String doInBackground(Void... params) { File dir = NMBAppConfig.getCookiesDir(); if (dir == null) { return null; } SimpleCookieStore cookieStore = NMBApplication.getSimpleCookieStore(mContext); List<TransportableHttpCookie> list = cookieStore.getTransportableCookies(); boolean ok; File file = new File(dir, ReadableTime.getFilenamableTime(System.currentTimeMillis())); FileWriter fileWriter = null; try { boolean first = true; fileWriter = new FileWriter(file); fileWriter.append('['); for (TransportableHttpCookie thc : list) { if (first) { first = false; } else { fileWriter.append(','); } fileWriter.append(JSON.toJSONString(thc)); } fileWriter.append(']'); fileWriter.flush(); ok = true; } catch (Exception e) { ok = false; } finally { IOUtils.closeQuietly(fileWriter); } if (!ok) { file.delete(); return null; } else { return file.getPath(); } } @Override protected void onPostExecute(String path) { mSaveCookies.setEnabled(true); Toast.makeText(mContext, path == null ? mContext.getString(R.string.save_cookies_failed) : mContext.getString(R.string.save_cookies_to, path), Toast.LENGTH_SHORT).show(); } } private class RestoreCookieDialogHelper implements DialogInterface.OnClickListener { private File[] mFiles; public RestoreCookieDialogHelper() { File dir = NMBAppConfig.getCookiesDir(); if (dir == null) { mFiles = new File[0]; } else { mFiles = dir.listFiles(); Arrays.sort(mFiles); } } private String[] getList() { int n = mFiles.length; String[] strings = new String[n + 1]; strings[0] = getString(R.string.clear_cookies); for (int i = 0; i < n; i++) { strings[i + 1] = mFiles[i].getName(); } return strings; } @Override public void onClick(@NonNull DialogInterface dialog, int which) { InputStream is = null; try { List<TransportableHttpCookie> list; if (which == 0) { list = new ArrayList<>(0); } else { File file = mFiles[which - 1]; is = new FileInputStream(file); String str = IOUtils.readString(is, "UTF-8"); list = JSON.parseArray(str, TransportableHttpCookie.class); } SimpleCookieStore cookieStore = NMBApplication.getSimpleCookieStore(getActivity()); cookieStore.removeAll(); for (TransportableHttpCookie thc : list) { // Fix for lost path bug if (TextUtils.isEmpty(thc.path)) { thc.path = "/"; } URL url; try { url = new URL(thc.url); } catch (MalformedURLException e) { continue; } HttpCookie cookie = thc.to(); if (cookie == null) { continue; } cookieStore.add(url, cookie); } NMBApplication.updateCookies(getActivity()); Toast.makeText(getActivity(), which == 0 ? R.string.clear_cookies_successfully : R.string.restore_cookies_successfully, Toast.LENGTH_SHORT).show(); } catch (Exception e) { Toast.makeText(getActivity(), R.string.not_valid_cookie_file, Toast.LENGTH_SHORT).show(); } finally { IOUtils.closeQuietly(is); // Restore timing setACCookiesSummary(-2); setACCookiesSummary(ACSite.getInstance().getCookieMaxAge(getActivity())); } } } private void updateFeedIdSummary() { mFeedId.setSummary(getActivity().getResources().getString( R.string.main_feed_id_summary, Settings.getFeedId())); } private class FeedIdDialogHelper implements View.OnClickListener { public View mView; public EditText mEditText; public View mPositive; public View mNegative; public View mNeutral; public Dialog mDialog; @SuppressLint("InflateParams") public FeedIdDialogHelper() { mView = getActivity().getLayoutInflater().inflate(R.layout.dialog_feed_id, null); mEditText = (EditText) mView.findViewById(R.id.edit_text); mEditText.setText(Settings.getFeedId()); } public View getView() { return mView; } public void setDialog(AlertDialog dialog) { mDialog = dialog; mPositive = dialog.getButton(DialogInterface.BUTTON_POSITIVE); mNegative = dialog.getButton(DialogInterface.BUTTON_NEGATIVE); mNeutral = dialog.getButton(DialogInterface.BUTTON_NEUTRAL); mPositive.setOnClickListener(this); mNegative.setOnClickListener(this); mNeutral.setOnClickListener(this); } @Override public void onClick(@NonNull View v) { if (mPositive == v) { String feedId = mEditText.getText().toString(); if (!TextUtils.isEmpty(feedId)) { Settings.putFeedId(feedId); mDialog.dismiss(); updateFeedIdSummary(); } else { Toast.makeText(getActivity(), R.string.invalid_feed_id, Toast.LENGTH_SHORT).show(); } } else if (mNegative == v) { mEditText.setText(Settings.getRandomFeedId()); } else if (mNeutral == v) { // mac mEditText.setText(Settings.getMacFeedId()); } } } public void updateImageSaveLocation() { UniFile uniFile = Settings.getImageSaveLocation(); if (uniFile == null) { mImageSaveLocation.setSummary(R.string.main_image_save_locatio_summary_invalid); } else { mImageSaveLocation.setSummary(uniFile.getUri().toString()); } } private boolean ensurePopupWindow() { View view = getView(); if (view == null) { return false; } ListView listView = (ListView) view.findViewById(android.R.id.list); if (listView == null) { return false; } view = listView.getChildAt(0); if (view == null) { return false; } view.getLocationInWindow(mLocation); if (!mPopupWindow.isShowing()) { mPopupWindow.showAtLocation(listView, Gravity.TOP | Gravity.LEFT, mLocation[0] + view.getWidth() / 3, mLocation[1]); mPopupWindow.update(view.getWidth() * 2 / 3, view.getHeight()); } else { mPopupWindow.update(mLocation[0] + view.getWidth() / 3, mLocation[1], view.getWidth() * 2 / 3, view.getHeight(), false); } return true; } public void getXuMing() { int click = mClick; // Get xu ming if (click % 10 < 9 || MathUtils.random(1.0f) < 0.95f) { switch (click / 10) { case 0: mXuMing = 1000; mXuMingStr = "+1s"; break; case 1: mXuMing = 60 * 1000; mXuMingStr = "+1m"; break; case 2: mXuMing = 60 * 60 * 1000; mXuMingStr = "+1h"; break; default: mXuMing = 24 * 60 * 60 * 1000; mXuMingStr = "+1d"; break; } } else { switch (click / 10) { case 0: mXuMing = -10 * 1000; mXuMingStr = "-10s"; break; case 1: mXuMing = -10 * 60 * 1000; mXuMingStr = "-10m"; break; case 2: mXuMing = -10 * 60 * 60 * 1000; mXuMingStr = "-10h"; break; default: mXuMing = -10 * 24 * 60 * 60 * 1000; mXuMingStr = "-10d"; break; } mClick = 0; } } @Override public boolean onPreferenceClick(Preference preference) { String key = preference.getKey(); if (KEY_AC_COOKIES.equals(key) && mTimingLife != null) { System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1); mHits[mHits.length - 1] = SystemClock.uptimeMillis(); if (mHits[0] >= (SystemClock.uptimeMillis() - 3000) && ensurePopupWindow()) { getXuMing(); if (mPopupTextView.popupText(mXuMingStr)) { mMaxAgeDiff += mXuMing; mTimingLife.update(mXuMing); mClick++; } } else { mClick = 0; } return true; } else if (KEY_SAVE_COOKIES.equals(key)) { mSaveCookies.setEnabled(false); new SaveCookieTask(getActivity()).execute(); return true; } else if (KEY_RESTORE_COOKIES.equals(key)) { RestoreCookieDialogHelper helper = new RestoreCookieDialogHelper(); String[] list = helper.getList(); if (list.length == 0) { Toast.makeText(getActivity(), R.string.cant_find_cookie_file, Toast.LENGTH_SHORT).show(); } else { new AlertDialog.Builder(getActivity()) .setTitle(R.string.select_cookie_file) .setItems(list, helper) .show(); } } else if (Settings.KEY_FEED_ID.equals(key)) { FeedIdDialogHelper helper = new FeedIdDialogHelper(); AlertDialog dialog = new AlertDialog.Builder(getActivity()) .setTitle(R.string.main_feed_id) .setView(helper.getView()) .setPositiveButton(android.R.string.ok, null) .setNegativeButton(R.string.random, null) .setNeutralButton(R.string.mac_addr, null) .show(); helper.setDialog(dialog); } else if (Settings.KEY_IMAGE_SAVE_LOACTION.equals(key)) { int sdk = Build.VERSION.SDK_INT; if (sdk < Build.VERSION_CODES.KITKAT) { openDirPicker(); } else if (sdk < Build.VERSION_CODES.LOLLIPOP) { showDirPickerDialogKK(); } else { showDirPickerDialogL(); } } else if (KEY_ABOUT_ANALYSIS.equals(key)) { try { CharSequence message = Html.fromHtml(IOUtils.readString( getResources().openRawResource(R.raw.about_analysis), "UTF-8")); Dialog dialog = new AlertDialog.Builder(getActivity()) .setTitle(R.string.data_analysis) .setMessage(message) .show(); TextView messageView = (TextView) dialog.findViewById(android.R.id.message); if (messageView != null) { messageView.setMovementMethod(new LinkMovementMethod2(getActivity())); } } catch (IOException e) { e.printStackTrace(); } } return true; } @Override @TargetApi(Build.VERSION_CODES.KITKAT) public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_CODE_PICK_IMAGE_DIR: if (resultCode == RESULT_OK) { UniFile uniFile = UniFile.fromUri(getActivity(), data.getData()); if (uniFile != null) { Settings.putImageSaveLocation(uniFile); updateImageSaveLocation(); } else { Toast.makeText(getActivity(), R.string.cant_get_image_save_location, Toast.LENGTH_SHORT).show(); } } break; case REQUEST_CODE_PICK_IMAGE_DIR_L: if (resultCode == RESULT_OK) { Uri treeUri = data.getData(); getActivity().getContentResolver().takePersistableUriPermission( treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); UniFile uniFile = UniFile.fromTreeUri(getActivity(), treeUri); if (uniFile != null) { Settings.putImageSaveLocation(uniFile); updateImageSaveLocation(); } else { Toast.makeText(getActivity(), R.string.cant_get_image_save_location, Toast.LENGTH_SHORT).show(); } } break; default: super.onActivityResult(requestCode, resultCode, data); } } private class TimingLife extends CountDownTimerEx { public TimingLife(long millisInFuture, long countDownInterval) { super(millisInFuture, countDownInterval); } @Override public void onTick(long millisUntilFinished) { setACCookiesSummary(millisUntilFinished / 1000); } @Override public void onFinish() { setACCookiesSummary(-2); mMaxAgeDiff = 0; mTimingLife = null; } } } public static class InfoFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener { private static final String KEY_AUTHOR = "author"; private static final String KEY_SOURCE = "source"; private static final String KEY_NOTICE = "notice"; private static final String KEY_VERSION = "version"; private static final String KEY_RELEASE_NOTES = "release_notes"; private static final String KEY_DUMP_LOGCAT = "dump_logcat"; private static final String KEY_HELP_NIMINGBAN = "help_nimingban"; private static final String KEY_HELP = "help"; private static final String KEY_DONATE = "donate"; private Preference mAuthor; private Preference mSource; private Preference mNotice; private Preference mVersion; private Preference mReleaseNotes; private Preference mDumpLogcat; private Preference mHelpNimingban; private Preference mHelp; private Preference mDonate; private boolean mShowTip = true; private final long[] mHits = new long[8]; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.info_settings); mAuthor = findPreference(KEY_AUTHOR); mSource = findPreference(KEY_SOURCE); mNotice = findPreference(KEY_NOTICE); mVersion = findPreference(KEY_VERSION); mReleaseNotes = findPreference(KEY_RELEASE_NOTES); mDumpLogcat = findPreference(KEY_DUMP_LOGCAT); mHelpNimingban = findPreference(KEY_HELP_NIMINGBAN); mHelp = findPreference(KEY_HELP); mDonate = findPreference(KEY_DONATE); mAuthor.setOnPreferenceClickListener(this); mSource.setOnPreferenceClickListener(this); mNotice.setOnPreferenceClickListener(this); mVersion.setOnPreferenceClickListener(this); mReleaseNotes.setOnPreferenceClickListener(this); mDumpLogcat.setOnPreferenceClickListener(this); mHelpNimingban.setOnPreferenceClickListener(this); mHelp.setOnPreferenceClickListener(this); mDonate.setOnPreferenceClickListener(this); mAuthor.setSummary("Hippo <hipposeven332$gmail.com>".replaceAll("\\$", "@")); try { PackageInfo packageInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0); mVersion.setSummary(packageInfo.versionName); } catch (PackageManager.NameNotFoundException e) { // Ignore } } @Override public boolean onPreferenceClick(Preference preference) { String key = preference.getKey(); if (KEY_AUTHOR.equals(key)) { ActivityHelper.sendEmail(getActivity(), "hipposeven332$gmail.com".replaceAll("\\$", "@"), "About Nimingban", null); } else if (KEY_SOURCE.equals(key)) { OpenUrlHelper.openUrl(getActivity(), "https://github.com/seven332/Nimingban", false); } else if (KEY_NOTICE.equals(key)) { try { String str = IOUtils.readString(getActivity().getResources().getAssets().open("NOTICE"), "UTF-8"); View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_notice, null); TextView tv = (TextView) view.findViewById(R.id.text); tv.setText(str); new AlertDialog.Builder(getActivity()).setView(view).show(); } catch (IOException e) { Toast.makeText(getActivity(), R.string.cant_open_notice, Toast.LENGTH_SHORT).show(); } } else if (KEY_VERSION.equals(key)) { System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1); mHits[mHits.length - 1] = SystemClock.uptimeMillis(); if (mHits[0] >= (SystemClock.uptimeMillis() - 3000)) { Arrays.fill(mHits, 0); if (mShowTip) { mShowTip = false; Toast.makeText(getActivity(), R.string.da_diao_tip, Toast.LENGTH_SHORT).show(); } else { Intent intent = new Intent(getActivity(), DaDiaoService.class); intent.setAction(DaDiaoService.ACTION_DA_DIAO); getActivity().startService(intent); } } } else if (KEY_RELEASE_NOTES.equals(key)) { OpenUrlHelper.openUrl(getActivity(), "http://nimingban.herokuapp.com/release_notes.html", false); } else if (KEY_DUMP_LOGCAT.equals(key)) { boolean ok; File file = null; File dir = NMBAppConfig.getLogcatDir(); if (dir != null) { file = new File(dir, "logcat-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".txt"); ok = LogCat.save(file); } else { ok = false; } Resources resources = getResources(); Toast.makeText(getActivity(), ok ? resources.getString(R.string.dump_logcat_to, file.getPath()) : resources.getString(R.string.dump_logcat_failed), Toast.LENGTH_SHORT).show(); } else if (KEY_HELP_NIMINGBAN.equals(key)) { new AlertDialog.Builder(getActivity()) .setTitle(R.string.help_nimingban_title) .setMessage(R.string.help_nimingban_message) .show(); } else if (KEY_HELP.equals(key)) { OpenUrlHelper.openUrl(getActivity(), "http://nimingban.herokuapp.com/help.html", false); } else if (KEY_DONATE.equals(key)) { new AlertDialog.Builder(getActivity()) .setTitle(R.string.main_donate) .setMessage(getString(R.string.donate_explain).replace('#', '@')) .show(); } return true; } } }