Commit 262a2ad1 authored by Amit Kumar's avatar Amit Kumar 💻
Browse files

Finish recent implementation

parent 160ab1a2
Pipeline #123977 failed with stage
in 1 minute and 8 seconds
......@@ -93,6 +93,7 @@ android {
apiQ {
java.srcDirs = ['src/apiOreo/java/foundation/e']
res.srcDirs = ['src/apiOreo/res']
manifest.srcFile "src/apiOreo/AndroidManifest.xml"
}
}
......@@ -108,7 +109,7 @@ dependencies {
compileOnly files('libs/framework.jar')
apiNougatImplementation 'org.cyanogenmod:platform.sdk:6.0'
apiOreoImplementation files('libs/lineage-sdk-oreo.jar')
apiQImplementation files('libs/lineage-sdk-q.jar')
debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'
implementation 'org.greenrobot:eventbus:3.1.1'
......
......@@ -38,6 +38,8 @@
<uses-permission android:name="lineageos.permission.READ_WEATHER" /> <!-- LineageOS specific permissions END -->
<uses-permission android:name="foundation.e.pwaplayer.provider.READ_WRITE" />
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
<application
android:name=".BlissLauncher"
android:hardwareAccelerated="true"
......@@ -174,7 +176,7 @@
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:theme="@style/LauncherTheme"
android:theme="@style/HomeScreenTheme"
android:screenOrientation="unspecified"
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:resizeableActivity="true"
......
package foundation.e.blisslauncher.core;
/**
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.util.Log;
/**
* {@link BroadcastReceiver} which watches configuration changes and
* restarts the process in case changes which affect the device profile occur.
*/
public class ConfigMonitor extends BroadcastReceiver {
private final Context mContext;
private final float mFontScale;
private final int mDensity;
public ConfigMonitor(Context context) {
mContext = context;
Configuration config = context.getResources().getConfiguration();
mFontScale = config.fontScale;
mDensity = config.densityDpi;
}
@Override
public void onReceive(Context context, Intent intent) {
Configuration config = context.getResources().getConfiguration();
if (mFontScale != config.fontScale || mDensity != config.densityDpi) {
Log.d("ConfigMonitor", "Configuration changed, restarting launcher");
mContext.unregisterReceiver(this);
android.os.Process.killProcess(android.os.Process.myPid());
}
}
public void register() {
mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
}
}
......@@ -228,7 +228,7 @@ public class IconsHandler {
}
}
private Drawable getBadgedIcon(Drawable icon, android.os.UserHandle userHandle) {
public Drawable getBadgedIcon(Drawable icon, android.os.UserHandle userHandle) {
return ctx.getApplicationContext().getPackageManager().getUserBadgedIcon(icon, userHandle);
}
......
/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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 foundation.e.blisslauncher.core;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.os.Handler;
import android.provider.Settings;
public interface SettingsObserver {
/**
* Registers the content observer to call {@link #onSettingChanged(boolean)} when any of the
* passed settings change. The value passed to onSettingChanged() is based on the key setting.
*/
void register(String keySetting, String ... dependentSettings);
void unregister();
void onSettingChanged(boolean keySettingEnabled);
abstract class Secure extends ContentObserver implements SettingsObserver {
private ContentResolver mResolver;
private String mKeySetting;
public Secure(ContentResolver resolver) {
super(new Handler());
mResolver = resolver;
}
@Override
public void register(String keySetting, String ... dependentSettings) {
mKeySetting = keySetting;
mResolver.registerContentObserver(
Settings.Secure.getUriFor(mKeySetting), false, this);
for (String setting : dependentSettings) {
mResolver.registerContentObserver(
Settings.Secure.getUriFor(setting), false, this);
}
onChange(true);
}
@Override
public void unregister() {
mResolver.unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
onSettingChanged(Settings.Secure.getInt(mResolver, mKeySetting, 1) == 1);
}
}
abstract class System extends ContentObserver implements SettingsObserver {
private ContentResolver mResolver;
private String mKeySetting;
public System(ContentResolver resolver) {
super(new Handler());
mResolver = resolver;
}
@Override
public void register(String keySetting, String ... dependentSettings) {
mKeySetting = keySetting;
mResolver.registerContentObserver(
Settings.System.getUriFor(mKeySetting), false, this);
for (String setting : dependentSettings) {
mResolver.registerContentObserver(
Settings.System.getUriFor(setting), false, this);
}
onChange(true);
}
@Override
public void unregister() {
mResolver.unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
onSettingChanged(Settings.System.getInt(mResolver, mKeySetting, 1) == 1);
}
}
}
package foundation.e.blisslauncher.core;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
......@@ -425,4 +427,9 @@ public class Utilities {
msg.setAsynchronous(true);
handler.sendMessage(msg);
}
public static SharedPreferences getPrefs(Context context) {
return context.getSharedPreferences(
"foundation.e.blisslauncher.prefs", Context.MODE_PRIVATE);
}
}
......@@ -12,10 +12,10 @@ import foundation.e.blisslauncher.core.blur.ShaderBlurDrawable
import foundation.e.blisslauncher.core.runOnMainThread
class DockGridLayout @JvmOverloads constructor(
private val mContext: Context,
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : GridLayout(mContext, attrs, defStyleAttr), Insettable,
) : GridLayout(context, attrs, defStyleAttr), Insettable,
BlurWallpaperProvider.Listener {
private val blurWallpaperProvider: BlurWallpaperProvider
private var fullBlurDrawable: ShaderBlurDrawable? = null
......@@ -44,13 +44,13 @@ class DockGridLayout @JvmOverloads constructor(
override fun onAttachedToWindow() {
super.onAttachedToWindow()
BlurWallpaperProvider.getInstance(mContext).addListener(this)
BlurWallpaperProvider.getInstance(context).addListener(this)
fullBlurDrawable!!.startListening()
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
BlurWallpaperProvider.getInstance(mContext).removeListener(this)
BlurWallpaperProvider.getInstance(context).removeListener(this)
fullBlurDrawable!!.stopListening()
}
......@@ -75,7 +75,7 @@ class DockGridLayout @JvmOverloads constructor(
override fun setInsets(insets: WindowInsets?) {
if (insets == null) return
val deviceProfile = BlissLauncher.getApplication(mContext).deviceProfile
val deviceProfile = BlissLauncher.getApplication(context).deviceProfile
val lp =
layoutParams as InsettableRelativeLayout.LayoutParams
lp.height = deviceProfile.hotseatCellHeightPx + insets.systemWindowInsetBottom
......@@ -104,7 +104,7 @@ class DockGridLayout @JvmOverloads constructor(
init {
setWillNotDraw(false)
blurWallpaperProvider = BlurWallpaperProvider.getInstance(mContext)
blurWallpaperProvider = BlurWallpaperProvider.getInstance(context)
createBlurDrawable()
}
}
\ No newline at end of file
......@@ -8,6 +8,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
import android.widget.FrameLayout
import foundation.e.blisslauncher.R
open class InsettableFrameLayout(private val mContext: Context, attrs: AttributeSet?) : FrameLayout(
mContext, attrs
......@@ -81,4 +82,21 @@ open class InsettableFrameLayout(private val mContext: Context, attrs: Attribute
}
}
}
open class LayoutParams : FrameLayout.LayoutParams {
var ignoreInsets = false
constructor(c: Context, attrs: AttributeSet?) : super(c, attrs) {
val a = c.obtainStyledAttributes(
attrs,
R.styleable.InsettableFrameLayout_Layout
)
ignoreInsets = a.getBoolean(
R.styleable.InsettableFrameLayout_Layout_layout_ignoreInsets, false
)
a.recycle()
}
constructor(width: Int, height: Int) : super(width, height) {}
constructor(lp: ViewGroup.LayoutParams?) : super(lp!!) {}
}
}
\ No newline at end of file
package foundation.e.blisslauncher.core.customviews;
import static foundation.e.blisslauncher.features.test.LauncherState.NORMAL;
import static foundation.e.blisslauncher.features.test.anim.LauncherAnimUtils.SPRING_LOADED_TRANSITION_MS;
import android.animation.Animator;
......@@ -7,6 +8,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.WallpaperManager;
import android.content.Context;
......@@ -22,11 +24,13 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.widget.GridLayout;
import android.widget.Toast;
import foundation.e.blisslauncher.BuildConfig;
import foundation.e.blisslauncher.R;
import foundation.e.blisslauncher.core.Utilities;
import foundation.e.blisslauncher.core.customviews.pageindicators.PageIndicatorDots;
import foundation.e.blisslauncher.core.database.model.ApplicationItem;
import foundation.e.blisslauncher.core.database.model.FolderItem;
......@@ -41,9 +45,13 @@ import foundation.e.blisslauncher.features.launcher.Hotseat;
import foundation.e.blisslauncher.features.test.Alarm;
import foundation.e.blisslauncher.features.test.CellLayout;
import foundation.e.blisslauncher.features.test.IconTextView;
import foundation.e.blisslauncher.features.test.LauncherState;
import foundation.e.blisslauncher.features.test.LauncherStateManager;
import foundation.e.blisslauncher.features.test.OnAlarmListener;
import foundation.e.blisslauncher.features.test.TestActivity;
import foundation.e.blisslauncher.features.test.VariantDeviceProfile;
import foundation.e.blisslauncher.features.test.WorkspaceStateTransitionAnimation;
import foundation.e.blisslauncher.features.test.anim.AnimatorSetBuilder;
import foundation.e.blisslauncher.features.test.dragndrop.DragController;
import foundation.e.blisslauncher.features.test.dragndrop.DragOptions;
import foundation.e.blisslauncher.features.test.dragndrop.DragSource;
......@@ -56,13 +64,18 @@ import java.util.List;
import org.jetbrains.annotations.NotNull;
public class LauncherPagedView extends PagedView<PageIndicatorDots> implements View.OnTouchListener,
Insettable, DropTarget, DragSource, DragController.DragListener {
Insettable, DropTarget, DragSource, DragController.DragListener,
LauncherStateManager.StateHandler {
private static final String TAG = "LauncherPagedView";
private static final int DEFAULT_PAGE = 0;
private static final int SNAP_OFF_EMPTY_SCREEN_DURATION = 400;
private static final int FADE_EMPTY_SCREEN_DURATION = 150;
/** The value that {@link #mTransitionProgress} must be greater than for
* {@link #isFinishedSwitchingState()} ()} to return true. */
private static final float FINISHED_SWITCHING_STATE_TRANSITION_PROGRESS = 0.5f;
private static final boolean MAP_NO_RECURSE = false;
private static final boolean MAP_RECURSE = true;
......@@ -129,6 +142,14 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
int mLastReorderX = -1;
int mLastReorderY = -1;
private IconTextView parentFolderCell;
private float mTransitionProgress;
private boolean mIsSwitchingState;
private boolean mForceDrawAdjacentPages;
private WorkspaceStateTransitionAnimation mStateTransitionAnimation;
float mLastOverlayScroll = 0;
boolean mOverlayShown = false;
private Runnable mOnOverlayHiddenCallback;
public LauncherPagedView(Context context, AttributeSet attributeSet) {
this(context, attributeSet, 0);
......@@ -138,6 +159,7 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
super(context, attributeSet, defStyle);
mLauncher = TestActivity.Companion.getLauncher(context);
mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this);
mWallpaperManager = WallpaperManager.getInstance(context);
setHapticFeedbackEnabled(false);
initWorkspace();
......@@ -779,22 +801,38 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
//return shouldConsumeTouch(v);
return true;
return shouldConsumeTouch(v);
}
private boolean shouldConsumeTouch(View v) {
return !workspaceIconsCanBeDragged()
|| (!workspaceInModalState() && indexOfChild(v) != mCurrentPage);
}
public boolean isSwitchingState() {
return false;
return mIsSwitchingState;
}
private boolean workspaceInModalState() {
return !mLauncher.isInState(NORMAL);
}
/**
* Returns whether a drag should be allowed to be started from the current workspace state.
*/
public boolean workspaceIconsCanBeDragged() {
return mLauncher.getStateManager().getState().workspaceIconsCanBeDragged;
}
/**
* This differs from isSwitchingState in that we take into account how far the transition
* has completed.
*/
/*public boolean isFinishedSwitchingState() {
public boolean isFinishedSwitchingState() {
return !mIsSwitchingState
|| (mTransitionProgress > FINISHED_SWITCHING_STATE_TRANSITION_PROGRESS);
}*/
}
@Override
public boolean dispatchUnhandledMove(View focused, int direction) {
return super.dispatchUnhandledMove(focused, direction);
......@@ -889,7 +927,7 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
}
private void updateChildrenLayersEnabled() {
boolean enableChildrenLayers = isPageInTransition();
boolean enableChildrenLayers = mIsSwitchingState || isPageInTransition();
if (enableChildrenLayers != mChildrenLayersEnabled) {
mChildrenLayersEnabled = enableChildrenLayers;
......@@ -912,6 +950,14 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
int leftScreen = visibleScreens[0];
int rightScreen = visibleScreens[1];
if (mForceDrawAdjacentPages) {
// In overview mode, make sure that the two side pages are visible.
leftScreen = Utilities.boundToRange(getCurrentPage() - 1, 0, rightScreen);
rightScreen = Utilities.boundToRange(getCurrentPage() + 1,
leftScreen, getPageCount() - 1
);
}
if (leftScreen == rightScreen) {
// make sure we're caching at least two pages always
if (rightScreen < screenCount - 1) {
......@@ -956,13 +1002,42 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
super.snapToDestination();
}
@Override
public boolean scrollLeft() {
boolean result = false;
if (!workspaceInModalState() && !mIsSwitchingState) {
result = super.scrollLeft();
}
// TODO: Fix this asap
/*Folder openFolder = Folder.getOpen(mLauncher);
if (openFolder != null) {
openFolder.completeDragExit();
}*/
return result;
}
@Override
public boolean scrollRight() {
boolean result = false;
if (!workspaceInModalState() && !mIsSwitchingState) {
result = super.scrollRight();
}
// TODO: Fix this asap
/*Folder openFolder = Folder.getOpen(mLauncher);
if (openFolder != null) {
openFolder.completeDragExit();
}*/
return result;
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
// Update the page indicator progress.
boolean isTransitioning =
(getLayoutTransition() != null && getLayoutTransition().isRunning());
mIsSwitchingState || (getLayoutTransition() != null && getLayoutTransition()
.isRunning());
if (!isTransitioning) {
showPageIndicatorAtCurrentScroll();
}
......@@ -1100,6 +1175,59 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
return true;
}
/**
* @return false if the callback is still pending
*/
private boolean tryRunOverlayCallback() {
if (mOnOverlayHiddenCallback == null) {
// Return true as no callback is pending. This is used by OnWindowFocusChangeListener
// to remove itself if multiple focus handles were added.
return true;
}
if (mOverlayShown || !hasWindowFocus()) {
return false;
}
mOnOverlayHiddenCallback.run();
mOnOverlayHiddenCallback = null;
return true;
}
/**
* Runs the given callback when the minus one overlay is hidden. Specifically, it is run
* when launcher's window has focus and the overlay is no longer being shown. If a callback
* is already present, the new callback will chain off it so both are run.
*
* @return Whether the callback was deferred.
*/
public boolean runOnOverlayHidden(Runnable callback) {
if (mOnOverlayHiddenCallback == null) {
mOnOverlayHiddenCallback = callback;
} else {
// Chain the new callback onto the previous callback(s).
Runnable oldCallback = mOnOverlayHiddenCallback;
mOnOverlayHiddenCallback = () -> {
oldCallback.run();
callback.run();
};
}
if (!tryRunOverlayCallback()) {
ViewTreeObserver observer = getViewTreeObserver();
if (observer != null && observer.isAlive()) {
observer.addOnWindowFocusChangeListener(
new ViewTreeObserver.OnWindowFocusChangeListener() {
@Override
public void onWindowFocusChanged(boolean hasFocus) {
if (tryRunOverlayCallback() && observer.isAlive()) {
observer.removeOnWindowFocusChangeListener(this);
}
}});
}
return true;
}
return false;
}
@Override
public void onDrop(DragObject d, DragOptions options) {
mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
......@@ -1910,6 +2038,56 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
}
}
private void onStartStateTransition(LauncherState state) {
mIsSwitchingState = true;
mTransitionProgress = 0;
updateChildrenLayersEnabled();
}
private void onEndStateTransition() {
mIsSwitchingState = false;
mForceDrawAdjacentPages = false;
mTransitionProgress = 1;
updateChildrenLayersEnabled();
}
/**
* Sets the current workspace {@link LauncherState} and updates the UI without any animations
*/
@Override
public void setState(LauncherState toState) {
onStartStateTransition(toState);
mStateTransitionAnimation.setState(toState);
onEndStateTransition();
}