Skip to content

Commit

Permalink
What's new implementation (#3441)
Browse files Browse the repository at this point in the history
Show what's new on first run
  • Loading branch information
keianhzo committed Jun 17, 2020
1 parent 20eff6d commit d3d2abf
Show file tree
Hide file tree
Showing 16 changed files with 301 additions and 14 deletions.
2 changes: 2 additions & 0 deletions app/build.gradle
Expand Up @@ -105,10 +105,12 @@ android {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig getUseDebugSigningOnRelease() ? debug.signingConfig : release.signingConfig
buildConfigField 'String', 'PROPS_ENDPOINT', '"http://mixedreality.mozilla.org/FirefoxReality/props.json"'
}
debug {
applicationIdSuffix getDevApplicationIdSuffix()
pseudoLocalesEnabled true
buildConfigField 'String', 'PROPS_ENDPOINT', '"http://mixedreality.mozilla.org/FirefoxReality/props.json"'
}
}

Expand Down
Expand Up @@ -2,16 +2,13 @@

import android.content.Context;
import android.content.SharedPreferences;
import android.database.Observable;
import android.graphics.Color;
import android.os.StrictMode;
import android.preference.PreferenceManager;
import android.util.Log;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.databinding.ObservableBoolean;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;

import org.json.JSONArray;
Expand All @@ -22,6 +19,8 @@
import org.mozilla.vrbrowser.BuildConfig;
import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.VRBrowserActivity;
import org.mozilla.vrbrowser.VRBrowserApplication;
import org.mozilla.vrbrowser.browser.engine.EngineProvider;
import org.mozilla.vrbrowser.telemetry.GleanMetricsService;
import org.mozilla.vrbrowser.telemetry.TelemetryWrapper;
import org.mozilla.vrbrowser.ui.viewmodel.SettingsViewModel;
Expand All @@ -30,11 +29,16 @@
import org.mozilla.vrbrowser.utils.StringUtils;
import org.mozilla.vrbrowser.utils.SystemUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import mozilla.components.concept.fetch.Request;
import mozilla.components.concept.fetch.Response;

import static org.mozilla.vrbrowser.utils.ServoUtils.isServoAvailable;

public class SettingsStore {
Expand Down Expand Up @@ -125,6 +129,46 @@ public void initModel(@NonNull Context context) {
ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) context).getApplication()))
.get(SettingsViewModel.class);
mSettingsViewModel.refresh();
update();
}

/**
* Synchronizes the remote properties with the settings storage and notifies the model.
* Any consumer listening to the SettingsViewModel will get notified of the properties updates.
*/
private void update() {
((VRBrowserApplication) mContext.getApplicationContext()).getExecutors().backgroundThread().post(() -> {
Request request = new Request(
BuildConfig.PROPS_ENDPOINT,
Request.Method.GET,
null,
null,
null,
null,
Request.Redirect.FOLLOW,
Request.CookiePolicy.INCLUDE,
false
);
try {
Response response = EngineProvider.INSTANCE.getDefaultClient(mContext).fetch(request);
if (response.getStatus() == 200) {
String json = response.getBody().string(StandardCharsets.UTF_8);
SharedPreferences.Editor editor = mPrefs.edit();
editor.putString(mContext.getString(R.string.settings_key_remote_props), json);
editor.commit();

mSettingsViewModel.setProps(json);

} else {
String json = mPrefs.getString(mContext.getString(R.string.settings_key_remote_props), null);
mSettingsViewModel.setProps(json);
}

} catch (IOException e) {
String json = mPrefs.getString(mContext.getString(R.string.settings_key_remote_props), null);
mSettingsViewModel.setProps(json);
}
});
}

public boolean isCrashReportingEnabled() {
Expand Down Expand Up @@ -738,5 +782,17 @@ public void setDownloadsSortingOrder(@SortingContextMenuWidget.Order int order)
public @Storage int getDownloadsSortingOrder() {
return mPrefs.getInt(mContext.getString(R.string.settings_key_downloads_sorting_order), DOWNLOADS_SORTING_ORDER_DEFAULT);
}
}

public void setRemotePropsVersionName(String versionName) {
SharedPreferences.Editor editor = mPrefs.edit();
editor.putString(mContext.getString(R.string.settings_key_remote_props_version_name), versionName);
editor.commit();

mSettingsViewModel.setPropsVersionName(versionName);
}

public String getRemotePropsVersionName() {
return mPrefs.getString(mContext.getString(R.string.settings_key_remote_props_version_name), "0");
}

}
Expand Up @@ -7,15 +7,28 @@
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.MutableLiveData;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import org.mozilla.geckoview.ContentBlocking;
import org.mozilla.vrbrowser.BuildConfig;
import org.mozilla.vrbrowser.browser.SettingsStore;
import org.mozilla.vrbrowser.utils.RemoteProperties;

import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Map;

public class SettingsViewModel extends AndroidViewModel {

private MutableLiveData<ObservableBoolean> isTrackingProtectionEnabled;
private MutableLiveData<ObservableBoolean> isDRMEnabled;
private MutableLiveData<ObservableBoolean> isPopupBlockingEnabled;
private MutableLiveData<ObservableBoolean> isWebXREnabled;
private MutableLiveData<String> propsVersionName;
private MutableLiveData<Map<String, RemoteProperties>> props;
private MutableLiveData<ObservableBoolean> isWhatsNewVisible;

public SettingsViewModel(@NonNull Application application) {
super(application);
Expand All @@ -24,21 +37,36 @@ public SettingsViewModel(@NonNull Application application) {
isDRMEnabled = new MutableLiveData<>(new ObservableBoolean(false));
isPopupBlockingEnabled = new MutableLiveData<>(new ObservableBoolean(false));
isWebXREnabled = new MutableLiveData<>(new ObservableBoolean(false));
propsVersionName = new MutableLiveData<>();
props = new MutableLiveData<>(Collections.emptyMap());
isWhatsNewVisible = new MutableLiveData<>(new ObservableBoolean(false));

propsVersionName.observeForever(props -> isWhatsNewVisible());
props.observeForever(versionName -> isWhatsNewVisible());
}

public void refresh() {
int level = SettingsStore.getInstance(getApplication().getBaseContext()).getTrackingProtectionLevel();
boolean isEnabled = level != ContentBlocking.EtpLevel.NONE;
isTrackingProtectionEnabled.setValue(new ObservableBoolean(isEnabled));
isTrackingProtectionEnabled.postValue(new ObservableBoolean(isEnabled));

boolean drmEnabled = SettingsStore.getInstance(getApplication().getBaseContext()).isDrmContentPlaybackEnabled();
isDRMEnabled = new MutableLiveData<>(new ObservableBoolean(drmEnabled));
isDRMEnabled.postValue(new ObservableBoolean(drmEnabled));

boolean popupBlockingEnabled = SettingsStore.getInstance(getApplication().getBaseContext()).isPopUpsBlockingEnabled();
isPopupBlockingEnabled = new MutableLiveData<>(new ObservableBoolean(popupBlockingEnabled));
isPopupBlockingEnabled.postValue(new ObservableBoolean(popupBlockingEnabled));

boolean webxrEnabled = SettingsStore.getInstance(getApplication().getBaseContext()).isWebXREnabled();
isWebXREnabled = new MutableLiveData<>(new ObservableBoolean(webxrEnabled));
isWebXREnabled.postValue(new ObservableBoolean(webxrEnabled));

String appVersionName = SettingsStore.getInstance(getApplication().getBaseContext()).getRemotePropsVersionName();
propsVersionName.postValue(appVersionName);
}

private void isWhatsNewVisible() {
boolean value = !BuildConfig.VERSION_NAME.equals(propsVersionName.getValue()) &&
props.getValue().containsKey(BuildConfig.VERSION_NAME);
isWhatsNewVisible.postValue(new ObservableBoolean(value));
}

public void setIsTrackingProtectionEnabled(boolean isEnabled) {
Expand Down Expand Up @@ -73,4 +101,26 @@ public MutableLiveData<ObservableBoolean> getIsWebXREnabled() {
return isWebXREnabled;
}

public void setPropsVersionName(String appVersionName) {
this.propsVersionName.setValue(appVersionName);
}

public MutableLiveData<String> getPropsVersionName() {
return propsVersionName;
}

public void setProps(String json) {
Gson gson = new GsonBuilder().create();
Type type = new TypeToken<Map<String, RemoteProperties>>() {}.getType();
this.props.postValue(gson.fromJson(json, type));
}

public MutableLiveData<Map<String, RemoteProperties>> getProps() {
return props;
}

public MutableLiveData<ObservableBoolean> getIsWhatsNewVisible() {
return isWhatsNewVisible;
}

}
Expand Up @@ -11,6 +11,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.ObservableBoolean;
import androidx.databinding.ObservableInt;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.MediatorLiveData;
import androidx.lifecycle.MutableLiveData;
Expand Down Expand Up @@ -71,6 +72,8 @@ public class WindowViewModel extends AndroidViewModel {
private MutableLiveData<ObservableBoolean> isDrmUsed;
private MediatorLiveData<ObservableBoolean> isUrlBarButtonsVisible;
private MediatorLiveData<ObservableBoolean> isUrlBarIconsVisible;
private MutableLiveData<ObservableInt> mWidth;
private MutableLiveData<ObservableInt> mHeight;

public WindowViewModel(Application application) {
super(application);
Expand Down Expand Up @@ -180,6 +183,9 @@ public WindowViewModel(Application application) {
isUrlBarIconsVisible.addSource(isLoading, mIsUrlBarIconsVisibleObserver);
isUrlBarIconsVisible.addSource(isInsecureVisible, mIsUrlBarIconsVisibleObserver);
isUrlBarIconsVisible.setValue(new ObservableBoolean(false));

mWidth = new MutableLiveData<>(new ObservableInt());
mHeight = new MutableLiveData<>(new ObservableInt());
}

private Observer<ObservableBoolean> mIsTopBarVisibleObserver = new Observer<ObservableBoolean>() {
Expand Down Expand Up @@ -373,6 +379,8 @@ public void refresh() {
isWebXRBlocked.postValue(isWebXRBlocked.getValue());
isTrackingEnabled.postValue(isTrackingEnabled.getValue());
isDrmUsed.postValue(isDrmUsed.getValue());
mWidth.postValue(mWidth.getValue());
mHeight.postValue(mHeight.getValue());
}

@NonNull
Expand Down Expand Up @@ -785,4 +793,22 @@ public MutableLiveData<ObservableBoolean> getIsUrlBarButtonsVisible() {
public MutableLiveData<ObservableBoolean> getIsUrlBarIconsVisible() {
return isUrlBarIconsVisible;
}

@NonNull
public MutableLiveData<ObservableInt> getWidth() {
return mWidth;
}

public void setWidth(int width) {
this.mWidth.setValue(new ObservableInt(width));
}

@NonNull
public MutableLiveData<ObservableInt> getHeight() {
return mHeight;
}

public void setHeight(int height) {
this.mHeight.setValue(new ObservableInt(height));
}
}
Expand Up @@ -15,7 +15,6 @@
import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.URLUtil;
import android.widget.EditText;
Expand All @@ -29,6 +28,7 @@

import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoSessionSettings;
import org.mozilla.vrbrowser.BuildConfig;
import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.VRBrowserActivity;
import org.mozilla.vrbrowser.VRBrowserApplication;
Expand All @@ -44,6 +44,7 @@
import org.mozilla.vrbrowser.search.suggestions.SuggestionsProvider;
import org.mozilla.vrbrowser.telemetry.GleanMetricsService;
import org.mozilla.vrbrowser.telemetry.TelemetryWrapper;
import org.mozilla.vrbrowser.ui.viewmodel.SettingsViewModel;
import org.mozilla.vrbrowser.ui.viewmodel.TrayViewModel;
import org.mozilla.vrbrowser.ui.viewmodel.WindowViewModel;
import org.mozilla.vrbrowser.ui.views.NavigationURLBar;
Expand All @@ -59,6 +60,7 @@
import org.mozilla.vrbrowser.ui.widgets.menus.VideoProjectionMenuWidget;
import org.mozilla.vrbrowser.utils.AnimationHelper;
import org.mozilla.vrbrowser.utils.ConnectivityReceiver;
import org.mozilla.vrbrowser.utils.RemoteProperties;
import org.mozilla.vrbrowser.utils.UrlUtils;

import java.util.ArrayList;
Expand Down Expand Up @@ -92,6 +94,7 @@ public interface NavigationListener {

private WindowViewModel mViewModel;
private TrayViewModel mTrayViewModel;
private SettingsViewModel mSettingsViewModel;
private NavigationBarBinding mBinding;
private AudioEngine mAudio;
private WindowWidget mAttachedWindow;
Expand Down Expand Up @@ -254,6 +257,14 @@ private void updateUI() {
}
});

mBinding.navigationBarNavigation.whatsNew.setOnClickListener(v -> {
SettingsStore.getInstance(getContext()).setRemotePropsVersionName(BuildConfig.VERSION_NAME);
RemoteProperties props = mSettingsViewModel.getProps().getValue().get(BuildConfig.VERSION_NAME);
if (props != null) {
mWidgetManager.openNewTabForeground(props.getWhatsNewUrl());
}
});

mBinding.navigationBarNavigation.menuButton.setOnClickListener(view -> {
view.requestFocusFromTouch();

Expand Down Expand Up @@ -510,6 +521,10 @@ public void detachFromWindow() {
mViewModel.getIsPopUpBlocked().removeObserver(mIsPopUpBlockedListener);
mViewModel = null;
}

if (mSettingsViewModel != null) {
mSettingsViewModel = null;
}
}

@Override
Expand All @@ -526,8 +541,15 @@ public void attachToWindow(@NonNull WindowWidget aWindow) {
(VRBrowserActivity)getContext(),
ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) getContext()).getApplication()))
.get(String.valueOf(mAttachedWindow.hashCode()), WindowViewModel.class);
mSettingsViewModel = new ViewModelProvider(
(VRBrowserActivity)getContext(),
ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) getContext()).getApplication()))
.get(SettingsViewModel.class);

mBinding.setViewmodel(mViewModel);
mBinding.setSettingsmodel(mSettingsViewModel);

mSettingsViewModel.refresh();

mViewModel.getIsActiveWindow().observeForever(mIsActiveWindowObserver);
mViewModel.getIsPopUpBlocked().observeForever(mIsPopUpBlockedListener);
Expand Down

0 comments on commit d3d2abf

Please sign in to comment.