Logger -> ErrorReporter

This commit is contained in:
serso 2016-01-14 16:03:57 +01:00
parent e015a12718
commit 91a8a1122b
26 changed files with 240 additions and 274 deletions

View File

@ -89,7 +89,7 @@ public abstract class AbstractCalculatorMathRegistry<T extends MathEntity, P ext
final JBuilder<? extends T> builder = createBuilder(entity); final JBuilder<? extends T> builder = createBuilder(entity);
add(builder); add(builder);
} catch (RuntimeException e) { } catch (RuntimeException e) {
Locator.getInstance().getLogger().error(null, e.getLocalizedMessage(), e); Locator.getInstance().getErrorReporter().onException(e);
notCreatedEntities.add(entity); notCreatedEntities.add(entity);
} }
} }
@ -107,7 +107,7 @@ public abstract class AbstractCalculatorMathRegistry<T extends MathEntity, P ext
} }
} catch (RuntimeException e) { } catch (RuntimeException e) {
// just in case // just in case
Locator.getInstance().getLogger().error(null, e.getLocalizedMessage(), e); Locator.getInstance().getErrorReporter().onException(e);
} }
} }

View File

@ -0,0 +1,40 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import org.acra.ACRA;
import javax.annotation.Nonnull;
public class AcraErrorReporter implements ErrorReporter {
@Override
public void onException(@Nonnull Throwable e) {
ACRA.getErrorReporter().reportBuilder().forceSilent().exception(e).send();
}
@Override
public void onError(@Nonnull String message) {
ACRA.getErrorReporter().reportBuilder().forceSilent().exception(new Throwable(message)).send();
}
}

View File

@ -1,64 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import android.util.Log;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 10/11/12
* Time: 12:15 AM
*/
public class AndroidCalculatorLogger implements CalculatorLogger {
@Nonnull
private static final String TAG = "Calculatorpp";
@Override
public void debug(@Nullable String tag, @Nonnull String message) {
Log.d(getTag(tag), message);
}
@Nonnull
private String getTag(@Nullable String tag) {
return tag != null ? TAG + "/" + tag : TAG;
}
@Override
public void debug(@Nullable String tag, @Nullable String message, @Nonnull Throwable e) {
Log.d(getTag(tag), message, e);
}
@Override
public void error(@Nullable String tag, @Nullable String message, @Nonnull Throwable e) {
Log.e(getTag(tag), message, e);
}
@Override
public void error(@Nullable String tag, @Nullable String message) {
Log.e(getTag(tag), message);
}
}

View File

@ -220,11 +220,6 @@ public final class App {
return Preferences.Widget.getTheme(getPreferences()); return Preferences.Widget.getTheme(getPreferences());
} }
@Nonnull
public static Executor getBackground() {
return background;
}
@Nonnull @Nonnull
public static Preferences.Gui.Theme getThemeFor(@Nonnull Context context) { public static Preferences.Gui.Theme getThemeFor(@Nonnull Context context) {
if (context instanceof CalculatorOnscreenService) { if (context instanceof CalculatorOnscreenService) {

View File

@ -6,25 +6,32 @@ import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
import dagger.Module;
import dagger.Provides;
import org.solovyev.android.UiThreadExecutor; import org.solovyev.android.UiThreadExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import dagger.Module;
import java.util.concurrent.ThreadFactory; import dagger.Provides;
@Module @Module
public class AppModule { public class AppModule {
@NonNull // single thread, should be used during the startup
public static final String THREAD_INIT = "thread-init"; public static final String THREAD_INIT = "thread-init";
@NonNull // UI application thread
public static final String THREAD_UI = "thread-ui"; public static final String THREAD_UI = "thread-ui";
// multiple threads
public static final String THREAD_BACKGROUND = "thread-background";
@NonNull @NonNull
private final Application application; private final Application application;
@ -75,6 +82,26 @@ public class AppModule {
}); });
} }
@Provides
@Singleton
@Named(THREAD_BACKGROUND)
Executor provideBackgroundThread() {
return Executors.newFixedThreadPool(5, new ThreadFactory() {
@NonNull
private final AtomicInteger counter = new AtomicInteger();
@Override
public Thread newThread(@Nonnull Runnable r) {
return new Thread(r, "Background #" + counter.getAndIncrement());
}
});
}
@Provides
@Singleton
ErrorReporter provideErrorReporter() {
return new AcraErrorReporter();
}
@Provides @Provides
@Singleton @Singleton
@Named(THREAD_UI) @Named(THREAD_UI)

View File

@ -58,6 +58,10 @@ public class CalculatorApplication extends android.app.Application implements Sh
@Named(AppModule.THREAD_INIT) @Named(AppModule.THREAD_INIT)
Executor initThread; Executor initThread;
@Inject
@Named(AppModule.THREAD_UI)
Executor uiThread;
@Inject @Inject
Handler handler; Handler handler;
@ -81,28 +85,29 @@ public class CalculatorApplication extends android.app.Application implements Sh
@Inject @Inject
Keyboard keyboard; Keyboard keyboard;
@Inject
@Named(AppModule.THREAD_UI)
Executor uiThread;
@Inject @Inject
History history; History history;
@Inject @Inject
Broadcaster broadcaster; Broadcaster broadcaster;
@Inject
ErrorReporter errorReporter;
@Override @Override
public void onCreate() { public void onCreate() {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final Languages languages = new Languages(preferences); final Languages languages = new Languages(preferences);
onPreCreate(preferences, languages); onPreCreate(preferences, languages);
super.onCreate();
component = DaggerAppComponent.builder() component = DaggerAppComponent.builder()
.appModule(new AppModule(this)) .appModule(new AppModule(this))
.build(); .build();
component.inject(this); component.inject(this);
history.init(initThread);
super.onCreate();
onPostCreate(preferences, languages); onPostCreate(preferences, languages);
} }
@ -117,7 +122,7 @@ public class CalculatorApplication extends android.app.Application implements Sh
new AndroidCalculatorEngine(this), new AndroidCalculatorEngine(this),
new AndroidCalculatorClipboard(this), new AndroidCalculatorClipboard(this),
new AndroidCalculatorNotifier(this), new AndroidCalculatorNotifier(this),
new AndroidCalculatorLogger(), errorReporter,
new AndroidCalculatorPreferenceService(this), new AndroidCalculatorPreferenceService(this),
keyboard, keyboard,
new AndroidCalculatorPlotter(this, new CalculatorPlotterImpl(calculator)) new AndroidCalculatorPlotter(this, new CalculatorPlotterImpl(calculator))

View File

@ -91,7 +91,7 @@ public class CalculatorDialogActivity extends ActionBarActivity {
final DialogData dialogData = readDialogData(getIntent()); final DialogData dialogData = readDialogData(getIntent());
if (dialogData == null) { if (dialogData == null) {
Locator.getInstance().getLogger().error(TAG, "Dialog data is null!"); Locator.getInstance().getErrorReporter().onError("Dialog data is null!");
this.finish(); this.finish();
} else { } else {
setContentView(R.layout.cpp_dialog); setContentView(R.layout.cpp_dialog);

View File

@ -185,8 +185,8 @@ public class CalculatorEngineImpl implements CalculatorEngine {
} }
private void logException(@Nonnull Exception e) { private void logException(@Nonnull Exception e) {
final CalculatorLogger logger = Locator.getInstance().getLogger(); final ErrorReporter errorReporter = Locator.getInstance().getErrorReporter();
logger.error("Engine", e.getMessage(), e); errorReporter.onException(e);
} }
@Override @Override

View File

@ -268,7 +268,7 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
result.toString(); result.toString();
if (messageRegistry.hasMessage()) { if (messageRegistry.hasMessage()) {
final CalculatorLogger logger = Locator.getInstance().getLogger(); final ErrorReporter errorReporter = Locator.getInstance().getErrorReporter();
try { try {
final List<Message> messages = new ArrayList<Message>(); final List<Message> messages = new ArrayList<Message>();
while (messageRegistry.hasMessage()) { while (messageRegistry.hasMessage()) {
@ -279,7 +279,7 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
} }
} catch (Throwable e) { } catch (Throwable e) {
// todo serso: not good but we need proper synchronization // todo serso: not good but we need proper synchronization
logger.error("Calculator", e.getMessage(), e); errorReporter.onException(e);
} }
} }

View File

@ -32,7 +32,7 @@ public interface CalculatorLocator {
@Nonnull CalculatorEngine engine, @Nonnull CalculatorEngine engine,
@Nonnull CalculatorClipboard clipboard, @Nonnull CalculatorClipboard clipboard,
@Nonnull CalculatorNotifier notifier, @Nonnull CalculatorNotifier notifier,
@Nonnull CalculatorLogger logger, @Nonnull ErrorReporter errorReporter,
@Nonnull CalculatorPreferenceService preferenceService, @Nonnull CalculatorPreferenceService preferenceService,
@Nonnull Keyboard keyboard, @Nonnull Keyboard keyboard,
@Nonnull CalculatorPlotter plotter); @Nonnull CalculatorPlotter plotter);
@ -53,7 +53,7 @@ public interface CalculatorLocator {
CalculatorNotifier getNotifier(); CalculatorNotifier getNotifier();
@Nonnull @Nonnull
CalculatorLogger getLogger(); ErrorReporter getErrorReporter();
@Nonnull @Nonnull
CalculatorPlotter getPlotter(); CalculatorPlotter getPlotter();

View File

@ -66,7 +66,7 @@ public class Display implements CalculatorEventListener {
@Inject @Inject
public Display(@Nonnull Calculator calculator) { public Display(@Nonnull Calculator calculator) {
this.lastEvent = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId()); lastEvent = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
calculator.addCalculatorEventListener(this); calculator.addCalculatorEventListener(this);
} }

View File

@ -27,7 +27,6 @@ import android.content.SharedPreferences;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.android.calculator.text.TextProcessorEditorResult; import org.solovyev.android.calculator.text.TextProcessorEditorResult;
import org.solovyev.android.calculator.view.EditorTextProcessor; import org.solovyev.android.calculator.view.EditorTextProcessor;
@ -43,7 +42,7 @@ public class Editor {
private static final String TAG = App.subTag("Editor"); private static final String TAG = App.subTag("Editor");
@Nullable @Nullable
private final TextProcessor<TextProcessorEditorResult, String> textProcessor; private final EditorTextProcessor textProcessor;
@Nullable @Nullable
private EditorView view; private EditorView view;
@Nonnull @Nonnull
@ -53,11 +52,7 @@ public class Editor {
@Inject @Inject
public Editor(@Nonnull SharedPreferences preferences) { public Editor(@Nonnull SharedPreferences preferences) {
this(new EditorTextProcessor(preferences)); textProcessor = new EditorTextProcessor(preferences);
}
public Editor(@Nullable TextProcessor<TextProcessorEditorResult, String> textProcessor) {
this.textProcessor = textProcessor;
} }
public static int clamp(int selection, @Nonnull CharSequence text) { public static int clamp(int selection, @Nonnull CharSequence text) {
@ -92,12 +87,8 @@ public class Editor {
public EditorState onTextChanged(@Nonnull EditorState newState) { public EditorState onTextChanged(@Nonnull EditorState newState) {
Check.isMainThread(); Check.isMainThread();
if (textProcessor != null) { if (textProcessor != null) {
try {
final TextProcessorEditorResult result = textProcessor.process(newState.getTextString()); final TextProcessorEditorResult result = textProcessor.process(newState.getTextString());
newState = EditorState.create(result.getCharSequence(), newState.selection + result.getOffset()); newState = EditorState.create(result.getCharSequence(), newState.selection + result.getOffset());
} catch (CalculatorParseException e) {
Locator.getInstance().getLogger().error(TAG, e.getMessage(), e);
}
} }
final EditorState oldState = state; final EditorState oldState = state;
state = newState; state = newState;

View File

@ -0,0 +1,30 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import javax.annotation.Nonnull;
public interface ErrorReporter {
void onException(@Nonnull Throwable e);
void onError(@Nonnull String message);
}

View File

@ -39,7 +39,7 @@ public class Locator implements CalculatorLocator {
@Nonnull @Nonnull
private CalculatorNotifier calculatorNotifier = new DummyCalculatorNotifier(); private CalculatorNotifier calculatorNotifier = new DummyCalculatorNotifier();
@Nonnull @Nonnull
private CalculatorLogger calculatorLogger = new SystemOutCalculatorLogger(); private ErrorReporter errorReporter = new SystemErrorReporter();
@Nonnull @Nonnull
private CalculatorClipboard calculatorClipboard = new DummyCalculatorClipboard(); private CalculatorClipboard calculatorClipboard = new DummyCalculatorClipboard();
@Nonnull @Nonnull
@ -61,7 +61,7 @@ public class Locator implements CalculatorLocator {
@Nonnull CalculatorEngine engine, @Nonnull CalculatorEngine engine,
@Nonnull CalculatorClipboard clipboard, @Nonnull CalculatorClipboard clipboard,
@Nonnull CalculatorNotifier notifier, @Nonnull CalculatorNotifier notifier,
@Nonnull CalculatorLogger logger, @Nonnull ErrorReporter errorReporter,
@Nonnull CalculatorPreferenceService preferenceService, @Nonnull CalculatorPreferenceService preferenceService,
@Nonnull Keyboard keyboard, @Nonnull Keyboard keyboard,
@Nonnull CalculatorPlotter plotter) { @Nonnull CalculatorPlotter plotter) {
@ -70,7 +70,7 @@ public class Locator implements CalculatorLocator {
this.calculatorEngine = engine; this.calculatorEngine = engine;
this.calculatorClipboard = clipboard; this.calculatorClipboard = clipboard;
this.calculatorNotifier = notifier; this.calculatorNotifier = notifier;
this.calculatorLogger = logger; this.errorReporter = errorReporter;
this.calculatorPreferenceService = preferenceService; this.calculatorPreferenceService = preferenceService;
this.calculatorPlotter = plotter; this.calculatorPlotter = plotter;
@ -113,8 +113,8 @@ public class Locator implements CalculatorLocator {
@Override @Override
@Nonnull @Nonnull
public CalculatorLogger getLogger() { public ErrorReporter getErrorReporter() {
return calculatorLogger; return errorReporter;
} }
@Nonnull @Nonnull

View File

@ -25,19 +25,15 @@ package org.solovyev.android.calculator;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
/** public class SystemErrorReporter implements ErrorReporter {
* User: serso
* Date: 10/11/12
* Time: 12:11 AM
*/
public interface CalculatorLogger {
void debug(@Nullable String tag, @Nonnull String message); @Override
public void onException(@Nonnull Throwable e) {
void debug(@Nullable String tag, @Nullable String message, @Nonnull Throwable e); e.printStackTrace(System.out);
}
void error(@Nullable String tag, @Nullable String message, @Nonnull Throwable e);
void error(@Nullable String tag, @Nullable String message);
@Override
public void onError(@Nullable String message) {
System.out.println(message);
}
} }

View File

@ -1,64 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 10/11/12
* Time: 12:12 AM
*/
public class SystemOutCalculatorLogger implements CalculatorLogger {
@Nonnull
private static final String TAG = SystemOutCalculatorLogger.class.getSimpleName();
@Override
public void debug(@Nullable String tag, @Nullable String message) {
System.out.println(getTag(tag) + ": " + message);
}
@Nonnull
private String getTag(@Nullable String tag) {
return tag != null ? tag : TAG;
}
@Override
public void debug(@Nullable String tag, @Nullable String message, @Nonnull Throwable e) {
debug(tag, message);
e.printStackTrace(System.out);
}
@Override
public void error(@Nullable String tag, @Nullable String message, @Nonnull Throwable e) {
System.out.println(getTag(tag) + ": " + message);
e.printStackTrace(System.out);
}
@Override
public void error(@Nullable String tag, @Nullable String message) {
System.out.println(getTag(tag) + ": " + message);
}
}

View File

@ -41,12 +41,13 @@ import org.solovyev.android.calculator.Display;
import org.solovyev.android.calculator.DisplayState; import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.Editor; import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.EditorState; import org.solovyev.android.calculator.EditorState;
import org.solovyev.android.calculator.Locator; import org.solovyev.android.calculator.ErrorReporter;
import org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences; import org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences;
import org.solovyev.android.io.FileLoader; import org.solovyev.android.io.FileLoader;
import org.solovyev.android.io.FileSaver; import org.solovyev.android.io.FileSaver;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
@ -65,6 +66,7 @@ import static android.text.TextUtils.isEmpty;
public class History { public class History {
public static final String TAG = App.subTag("History"); public static final String TAG = App.subTag("History");
public static final String OLD_HISTORY_PREFS_KEY = "org.solovyev.android.calculator.CalculatorModel_history";
private static final ChangedEvent CHANGED_EVENT_RECENT = new ChangedEvent(true); private static final ChangedEvent CHANGED_EVENT_RECENT = new ChangedEvent(true);
private static final ChangedEvent CHANGED_EVENT_SAVED = new ChangedEvent(false); private static final ChangedEvent CHANGED_EVENT_SAVED = new ChangedEvent(false);
private static final int MAX_INTERMEDIATE_STREAK = 5; private static final int MAX_INTERMEDIATE_STREAK = 5;
@ -76,29 +78,23 @@ public class History {
private final RecentHistory recent = new RecentHistory(); private final RecentHistory recent = new RecentHistory();
@Nonnull @Nonnull
private final List<HistoryState> saved = new ArrayList<>(); private final List<HistoryState> saved = new ArrayList<>();
@Nonnull @Inject
private final Application application; Application application;
@Nonnull @Inject
private final Bus bus; Bus bus;
@Inject @Inject
Handler handler; Handler handler;
@Inject @Inject
SharedPreferences preferences; SharedPreferences preferences;
@Inject @Inject
Editor editor; Editor editor;
@Inject @Inject
public History(@NonNull Application application, @NonNull Bus bus, @Nonnull @Named(AppModule.THREAD_INIT) Executor initThread) { Display display;
this.application = application; @Inject
this.bus = bus; ErrorReporter errorReporter;
this.bus.register(this); @Inject
initThread.execute(new Runnable() { @Named(AppModule.THREAD_BACKGROUND)
@Override Executor backgroundThread;
public void run() {
init();
}
});
}
@Nullable @Nullable
static List<HistoryState> convertOldHistory(@NonNull String xml) { static List<HistoryState> convertOldHistory(@NonNull String xml) {
@ -120,7 +116,7 @@ public class History {
} }
@Nonnull @Nonnull
static List<HistoryState> loadStates(@Nonnull File file) { static List<HistoryState> loadStates(@Nonnull File file) throws IOException, JSONException {
if (!file.exists()) { if (!file.exists()) {
return Collections.emptyList(); return Collections.emptyList();
} }
@ -128,12 +124,7 @@ public class History {
if (isEmpty(json)) { if (isEmpty(json)) {
return Collections.emptyList(); return Collections.emptyList();
} }
try {
return RecentHistory.fromJson(new JSONArray(json.toString())); return RecentHistory.fromJson(new JSONArray(json.toString()));
} catch (JSONException e) {
Locator.getInstance().getLogger().error(TAG, e.getMessage(), e);
}
return Collections.emptyList();
} }
private static boolean isIntermediate(@Nonnull String olderText, private static boolean isIntermediate(@Nonnull String olderText,
@ -183,6 +174,21 @@ public class History {
return sb.toString(); return sb.toString();
} }
@Inject
public History() {
}
public void init(@NonNull Executor initThread) {
Check.isMainThread();
bus.register(this);
initThread.execute(new Runnable() {
@Override
public void run() {
initAsync();
}
});
}
@NonNull @NonNull
private File getSavedHistoryFile() { private File getSavedHistoryFile() {
return new File(application.getFilesDir(), "history-saved.json"); return new File(application.getFilesDir(), "history-saved.json");
@ -195,7 +201,7 @@ public class History {
private void migrateOldHistory() { private void migrateOldHistory() {
try { try {
final String xml = preferences.getString("org.solovyev.android.calculator.CalculatorModel_history", null); final String xml = preferences.getString(OLD_HISTORY_PREFS_KEY, null);
if (isEmpty(xml)) { if (isEmpty(xml)) {
return; return;
} }
@ -205,16 +211,17 @@ public class History {
} }
final JSONArray json = RecentHistory.toJson(states); final JSONArray json = RecentHistory.toJson(states);
FileSaver.save(getSavedHistoryFile(), json.toString()); FileSaver.save(getSavedHistoryFile(), json.toString());
} catch (Exception e) { preferences.edit().remove(OLD_HISTORY_PREFS_KEY).apply();
Locator.getInstance().getLogger().error(TAG, e.getMessage(), e); } catch (IOException e) {
errorReporter.onException(e);
} }
} }
private void init() { private void initAsync() {
Check.isNotMainThread(); Check.isNotMainThread();
migrateOldHistory(); migrateOldHistory();
final List<HistoryState> recentStates = loadStates(getRecentHistoryFile()); final List<HistoryState> recentStates = tryLoadStates(getRecentHistoryFile());
final List<HistoryState> savedStates = loadStates(getSavedHistoryFile()); final List<HistoryState> savedStates = tryLoadStates(getSavedHistoryFile());
handler.post(new Runnable() { handler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -226,6 +233,16 @@ public class History {
}); });
} }
@Nonnull
private List<HistoryState> tryLoadStates(@NonNull File file) {
try {
return loadStates(file);
} catch (IOException | JSONException e) {
errorReporter.onException(e);
}
return Collections.emptyList();
}
public void addRecent(@Nonnull HistoryState state) { public void addRecent(@Nonnull HistoryState state) {
Check.isMainThread(); Check.isMainThread();
recent.add(state); recent.add(state);
@ -318,8 +335,8 @@ public class History {
} }
private void applyHistoryState(@Nonnull HistoryState state) { private void applyHistoryState(@Nonnull HistoryState state) {
App.getEditor().setState(state.editor); editor.setState(state.editor);
App.getDisplay().setState(state.display); display.setState(state.display);
} }
public void removeSaved(@Nonnull HistoryState state) { public void removeSaved(@Nonnull HistoryState state) {
@ -364,12 +381,16 @@ public class History {
Check.isMainThread(); Check.isMainThread();
// don't need to save intermediate states, thus {@link History#getRecent} // don't need to save intermediate states, thus {@link History#getRecent}
final List<HistoryState> states = recent ? getRecent() : getSaved(); final List<HistoryState> states = recent ? getRecent() : getSaved();
App.getBackground().execute(new Runnable() { backgroundThread.execute(new Runnable() {
@Override @Override
public void run() { public void run() {
final File file = recent ? getRecentHistoryFile() : getSavedHistoryFile(); final File file = recent ? getRecentHistoryFile() : getSavedHistoryFile();
final JSONArray array = RecentHistory.toJson(states); final JSONArray array = RecentHistory.toJson(states);
try {
FileSaver.save(file, array.toString()); FileSaver.save(file, array.toString());
} catch (IOException e) {
errorReporter.onException(e);
}
} }
}); });
} }

View File

@ -2,17 +2,14 @@ package org.solovyev.android.calculator.view;
import android.app.Application; import android.app.Application;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.util.Log;
import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.Preferences; import org.solovyev.android.calculator.Preferences;
import org.solovyev.android.calculator.text.TextProcessor; import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.android.calculator.text.TextProcessorEditorResult; import org.solovyev.android.calculator.text.TextProcessorEditorResult;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject;
import static org.solovyev.android.calculator.Preferences.Gui.colorDisplay; import static org.solovyev.android.calculator.Preferences.Gui.colorDisplay;
import static org.solovyev.android.calculator.Preferences.Gui.theme; import static org.solovyev.android.calculator.Preferences.Gui.theme;
@ -22,7 +19,7 @@ public final class EditorTextProcessor implements TextProcessor<TextProcessorEdi
private boolean highlightText = true; private boolean highlightText = true;
@Nullable @Nullable
private TextProcessor<TextProcessorEditorResult, String> textHighlighter; private TextHighlighter textHighlighter;
public EditorTextProcessor(@Nonnull SharedPreferences preferences) { public EditorTextProcessor(@Nonnull SharedPreferences preferences) {
preferences.registerOnSharedPreferenceChangeListener(this); preferences.registerOnSharedPreferenceChangeListener(this);
@ -31,30 +28,16 @@ public final class EditorTextProcessor implements TextProcessor<TextProcessorEdi
@Nonnull @Nonnull
@Override @Override
public TextProcessorEditorResult process(@Nonnull String text) throws CalculatorParseException { public TextProcessorEditorResult process(@Nonnull String text) {
TextProcessorEditorResult result; if (!highlightText) {
return new TextProcessorEditorResult(text, 0);
if (highlightText) { }
try {
final TextProcessorEditorResult processesText = getTextHighlighter().process(text); final TextProcessorEditorResult processesText = getTextHighlighter().process(text);
return new TextProcessorEditorResult(processesText.getCharSequence(), processesText.getOffset());
result = new TextProcessorEditorResult(processesText.getCharSequence(), processesText.getOffset());
} catch (CalculatorParseException e) {
// set raw text
result = new TextProcessorEditorResult(text, 0);
Log.e(this.getClass().getName(), e.getMessage(), e);
}
} else {
result = new TextProcessorEditorResult(text, 0);
}
return result;
} }
@Nonnull @Nonnull
private TextProcessor<TextProcessorEditorResult, String> getTextHighlighter() { private TextHighlighter getTextHighlighter() {
if (textHighlighter == null) { if (textHighlighter == null) {
onSharedPreferenceChanged(App.getPreferences(), theme.getKey()); onSharedPreferenceChanged(App.getPreferences(), theme.getKey());
} }

View File

@ -26,17 +26,24 @@ import android.graphics.Typeface;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan; import android.text.style.StyleSpan;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.BaseNumberBuilder;
import org.solovyev.android.calculator.CalculatorEngine;
import org.solovyev.android.calculator.LiteNumberBuilder;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.NumberBuilder;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.text.TextProcessor; import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.android.calculator.text.TextProcessorEditorResult; import org.solovyev.android.calculator.text.TextProcessorEditorResult;
import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
public class TextHighlighter implements TextProcessor<TextProcessorEditorResult, String> { public class TextHighlighter implements TextProcessor<TextProcessorEditorResult, String> {
private final int red; private final int red;
@ -76,7 +83,7 @@ public class TextHighlighter implements TextProcessor<TextProcessorEditorResult,
@Nonnull @Nonnull
@Override @Override
public TextProcessorEditorResult process(@Nonnull String text) throws CalculatorParseException { public TextProcessorEditorResult process(@Nonnull String text) {
final CalculatorEngine engine = Locator.getInstance().getEngine(); final CalculatorEngine engine = Locator.getInstance().getEngine();
final SpannableStringBuilder sb = new SpannableStringBuilder(); final SpannableStringBuilder sb = new SpannableStringBuilder();
final BaseNumberBuilder nb = !formatNumber ? new LiteNumberBuilder(engine) : new NumberBuilder(engine); final BaseNumberBuilder nb = !formatNumber ? new LiteNumberBuilder(engine) : new NumberBuilder(engine);

View File

@ -1,7 +1,6 @@
package org.solovyev.android.io; package org.solovyev.android.io;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
@ -11,7 +10,7 @@ import java.io.InputStreamReader;
public abstract class BaseIoLoader { public abstract class BaseIoLoader {
@Nullable @Nullable
public CharSequence load() { public CharSequence load() throws IOException {
BufferedReader reader = null; BufferedReader reader = null;
try { try {
final InputStream is = getInputStream(); final InputStream is = getInputStream();
@ -26,12 +25,9 @@ public abstract class BaseIoLoader {
line = reader.readLine(); line = reader.readLine();
} }
return result; return result;
} catch (IOException e) {
Log.e(getClass().getSimpleName(), e.getMessage(), e);
} finally { } finally {
Io.close(reader); Io.close(reader);
} }
return null;
} }
@Nullable @Nullable

View File

@ -1,14 +1,13 @@
package org.solovyev.android.io; package org.solovyev.android.io;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
public abstract class BaseIoSaver implements Runnable { public abstract class BaseIoSaver {
@NonNull @NonNull
private final CharSequence data; private final CharSequence data;
@ -17,13 +16,11 @@ public abstract class BaseIoSaver implements Runnable {
this.data = data; this.data = data;
} }
public void save() { public void save() throws IOException {
OutputStreamWriter out = null; OutputStreamWriter out = null;
try { try {
out = new OutputStreamWriter(getOutputStream()); out = new OutputStreamWriter(getOutputStream());
out.write(data.toString()); out.write(data.toString());
} catch (IOException e) {
Log.e("FileSaver", e.getMessage(), e);
} finally { } finally {
Io.close(out); Io.close(out);
} }
@ -31,9 +28,4 @@ public abstract class BaseIoSaver implements Runnable {
@NonNull @NonNull
protected abstract FileOutputStream getOutputStream() throws FileNotFoundException; protected abstract FileOutputStream getOutputStream() throws FileNotFoundException;
@Override
public void run() {
save();
}
} }

View File

@ -18,7 +18,7 @@ public class FileLoader extends BaseIoLoader {
} }
@Nullable @Nullable
public static CharSequence load(@NonNull File file) { public static CharSequence load(@NonNull File file) throws IOException {
final FileLoader loader = new FileLoader(file); final FileLoader loader = new FileLoader(file);
return loader.load(); return loader.load();
} }

View File

@ -5,6 +5,7 @@ import android.support.annotation.NonNull;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException;
public class FileSaver extends BaseIoSaver { public class FileSaver extends BaseIoSaver {
@ -16,7 +17,7 @@ public class FileSaver extends BaseIoSaver {
this.file = file; this.file = file;
} }
public static void save(@NonNull File file, @NonNull CharSequence data) { public static void save(@NonNull File file, @NonNull CharSequence data) throws IOException {
final FileSaver fileSaver = new FileSaver(file, data); final FileSaver fileSaver = new FileSaver(file, data);
fileSaver.save(); fileSaver.save();
} }

View File

@ -36,7 +36,7 @@ import java.util.concurrent.Executor;
public class AbstractCalculatorTest { public class AbstractCalculatorTest {
protected void setUp() throws Exception { protected void setUp() throws Exception {
Locator.getInstance().init(new CalculatorImpl(Mockito.mock(Bus.class), Mockito.mock(Executor.class)), CalculatorTestUtils.newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemOutCalculatorLogger(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class)); Locator.getInstance().init(new CalculatorImpl(Mockito.mock(Bus.class), Mockito.mock(Executor.class)), CalculatorTestUtils.newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemErrorReporter(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class));
Locator.getInstance().getEngine().init(); Locator.getInstance().getEngine().init();
} }

View File

@ -23,8 +23,9 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.content.Context; import android.content.Context;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
import jscl.JsclMathEngine;
import org.junit.Assert; import org.junit.Assert;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.robolectric.fakes.RoboSharedPreferences; import org.robolectric.fakes.RoboSharedPreferences;
@ -32,9 +33,12 @@ import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.language.Languages; import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.calculator.plot.CalculatorPlotter; import org.solovyev.android.calculator.plot.CalculatorPlotter;
import javax.annotation.Nonnull; import java.io.ByteArrayInputStream;
import javax.annotation.Nullable; import java.io.ByteArrayOutputStream;
import java.io.*; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.text.DecimalFormatSymbols; import java.text.DecimalFormatSymbols;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -42,6 +46,11 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.JsclMathEngine;
/** /**
* User: serso * User: serso
* Date: 10/7/12 * Date: 10/7/12
@ -54,7 +63,7 @@ public class CalculatorTestUtils {
public static void staticSetUp() throws Exception { public static void staticSetUp() throws Exception {
App.init(new CalculatorApplication(), new Languages(new RoboSharedPreferences(new HashMap<String, Map<String, Object>>(), "test", 0))); App.init(new CalculatorApplication(), new Languages(new RoboSharedPreferences(new HashMap<String, Map<String, Object>>(), "test", 0)));
Locator.getInstance().init(new CalculatorImpl(Mockito.mock(Bus.class), Mockito.mock(Executor.class)), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemOutCalculatorLogger(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class)); Locator.getInstance().init(new CalculatorImpl(Mockito.mock(Bus.class), Mockito.mock(Executor.class)), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemErrorReporter(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class));
Locator.getInstance().getEngine().init(); Locator.getInstance().getEngine().init();
final DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols(); final DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols();
@ -64,7 +73,7 @@ public class CalculatorTestUtils {
} }
public static void staticSetUp(@Nullable Context context) throws Exception { public static void staticSetUp(@Nullable Context context) throws Exception {
Locator.getInstance().init(new CalculatorImpl(Mockito.mock(Bus.class), Mockito.mock(Executor.class)), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemOutCalculatorLogger(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class)); Locator.getInstance().init(new CalculatorImpl(Mockito.mock(Bus.class), Mockito.mock(Executor.class)), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemErrorReporter(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class));
Locator.getInstance().getEngine().init(); Locator.getInstance().getEngine().init();
if (context != null) { if (context != null) {

View File

@ -43,7 +43,6 @@ import org.solovyev.android.calculator.jscl.JsclOperation;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -65,7 +64,9 @@ public class HistoryTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
history = new History(RuntimeEnvironment.application, mock(Bus.class), mock(Executor.class)); history = new History();
history.application = RuntimeEnvironment.application;
history.bus = mock(Bus.class);
history.handler = mock(Handler.class); history.handler = mock(Handler.class);
history.preferences = mock(SharedPreferences.class); history.preferences = mock(SharedPreferences.class);
history.editor = mock(Editor.class); history.editor = mock(Editor.class);