diff options
Diffstat (limited to 'KBars/app')
27 files changed, 1840 insertions, 0 deletions
diff --git a/KBars/app/build.gradle b/KBars/app/build.gradle new file mode 100644 index 0000000..eee6df5 --- /dev/null +++ b/KBars/app/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'com.android.application' + +apply plugin: 'kotlin-android' + +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 26 + buildToolsVersion "26.0.0" + defaultConfig { + applicationId "js.kbars" + minSdkVersion 19 + targetSdkVersion 26 + versionCode 100 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" + implementation 'com.android.support:appcompat-v7:25.4.0' + testImplementation 'junit:junit:4.12' +} diff --git a/KBars/app/src/main/AndroidManifest.xml b/KBars/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..f330c7b --- /dev/null +++ b/KBars/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="js.kbars"> + <uses-feature android:name="android.hardware.camera" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="26" /> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <application android:theme="@style/AppTheme" android:label="@string/app_name" android:icon="@drawable/ic_launcher" android:debuggable="true" android:allowBackup="true"> + <activity android:label="@string/app_name" android:name=".KBarsActivity" android:launchMode="singleTask"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity android:label="DropShadowActivity" android:name=".DropShadowActivity"> + </activity> + <activity android:label="(kbars-toast)" android:name=".ToastActivity" android:launchMode="singleTask"> + </activity> + <service android:label="(kbars-dream)" android:name=".KBarsDream" android:exported="true"> + <intent-filter> + <action android:name="android.service.dreams.DreamService" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </service> + <activity android:label="(kbars-car)" android:name=".KBarsCar" android:exported="true" android:launchMode="singleTask"> + <meta-data android:name="android.dock_home" android:value="true" /> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.CAR_DOCK" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/KBars/app/src/main/assets/background.png b/KBars/app/src/main/assets/background.png Binary files differnew file mode 100644 index 0000000..aae8a33 --- /dev/null +++ b/KBars/app/src/main/assets/background.png diff --git a/KBars/app/src/main/java/js/kbars/CameraBackgroundMenuItem.java b/KBars/app/src/main/java/js/kbars/CameraBackgroundMenuItem.java new file mode 100644 index 0000000..8d25d34 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/CameraBackgroundMenuItem.java @@ -0,0 +1,102 @@ +package js.kbars; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MenuItem.OnMenuItemClickListener; +import android.view.View; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +public final class CameraBackgroundMenuItem implements OnMenuItemClickListener { + public static final int REQUEST_CODE = 123; + private final Activity mActivity; + private final View mTarget; + + public CameraBackgroundMenuItem(Menu menu, Activity activity, View target) { + this.mActivity = activity; + this.mTarget = target; + menu.add("Camera image background...").setOnMenuItemClickListener(this); + loadBitmap(); + } + + public boolean onMenuItemClick(MenuItem item) { + chooseBackground(); + return true; + } + + public void onActivityResult(int resultCode, Intent data) { + if (resultCode == -1) { + Bitmap bitmap = (Bitmap) data.getParcelableExtra("data"); + if (bitmap != null) { + setTargetBackground(bitmap); + saveBitmap(bitmap); + } + } + } + + private void chooseBackground() { + this.mActivity.startActivityForResult(new Intent("android.media.action.IMAGE_CAPTURE"), REQUEST_CODE); + } + + private File bitmapFile() { + return new File(this.mActivity.getCacheDir(), "background.png"); + } + + private void saveBitmap(Bitmap bitmap) { + FileNotFoundException e; + Throwable th; + File f = bitmapFile(); + if (f.exists()) { + f.delete(); + } + if (bitmap != null) { + FileOutputStream out = null; + try { + FileOutputStream out2 = new FileOutputStream(f); + bitmap.compress(CompressFormat.PNG, 100, out2); + out2.close(); + } catch (FileNotFoundException e1) { + e1.printStackTrace(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + + private void loadBitmap() { + Bitmap bitmap = loadBitmapFromCache(); + if (bitmap == null) { + bitmap = loadBitmapFromAssets(); + } + setTargetBackground(bitmap); + } + + private Bitmap loadBitmapFromCache() { + File f = bitmapFile(); + return f.exists() ? BitmapFactory.decodeFile(f.getAbsolutePath()) : null; + } + + private Bitmap loadBitmapFromAssets() { + try { + return BitmapFactory.decodeStream(this.mActivity.getAssets().open("background.png")); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void setTargetBackground(Bitmap bitmap) { + if (bitmap == null) { + this.mTarget.setBackground(null); + } else { + this.mTarget.setBackground(new BitmapDrawable(this.mActivity.getResources(), bitmap)); + } + } +} diff --git a/KBars/app/src/main/java/js/kbars/DropShadowActivity.java b/KBars/app/src/main/java/js/kbars/DropShadowActivity.java new file mode 100644 index 0000000..79577d9 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/DropShadowActivity.java @@ -0,0 +1,40 @@ +package js.kbars; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.BitmapFactory; +import android.graphics.BlurMaskFilter; +import android.graphics.BlurMaskFilter.Blur; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Bundle; +import android.widget.ImageView; +import android.widget.ImageView.ScaleType; + +public class DropShadowActivity extends Activity { + private final Context mContext = this; + private ImageView mImageView; + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.mImageView = new ImageView(this.mContext); + this.mImageView.setBackgroundColor(-1); + this.mImageView.setScaleType(ScaleType.CENTER); + this.mImageView.setScaleX(1.0f); + this.mImageView.setScaleY(1.0f); + setContentView(this.mImageView); + setImage(); + } + + private void setImage() { + BlurMaskFilter blurFilter = new BlurMaskFilter(1.0f, Blur.SOLID); + Paint shadowPaint = new Paint(); + int[] offsetXY = new int[2]; + Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), 17301624); + Bitmap shadowImage32 = originalBitmap.extractAlpha(shadowPaint, offsetXY).copy(Config.ARGB_8888, true); + new Canvas(shadowImage32).drawBitmap(originalBitmap, (float) ((-offsetXY[0]) - 10), (float) ((-offsetXY[1]) - 10), null); + this.mImageView.setImageBitmap(shadowImage32); + } +} diff --git a/KBars/app/src/main/java/js/kbars/FitSystemWindowsActivity.java b/KBars/app/src/main/java/js/kbars/FitSystemWindowsActivity.java new file mode 100644 index 0000000..35ff6ae --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/FitSystemWindowsActivity.java @@ -0,0 +1,184 @@ +package js.kbars; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.Handler; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnSystemUiVisibilityChangeListener; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.LinearLayout; +import android.widget.TextView; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class FitSystemWindowsActivity extends Activity { + private static final int SYSTEM_UI_CLEARABLE_FLAGS = 7; + private static final int SYSTEM_UI_FLAG_ALLOW_TRANSIENT = 2048; + private static final int SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION = 8192; + private static final int SYSTEM_UI_FLAG_TRANSPARENT_STATUS = 4096; + private final Context mContext = this; + private FlagStateTextView mFlagStateTextView; + private final Handler mHandler = new Handler(); + private LinearLayout mLayout; + private final Runnable mUpdateText = new Runnable() { + public void run() { + FitSystemWindowsActivity.this.mFlagStateTextView.updateText(); + } + }; + + private static class Flag implements Comparable<Flag> { + public static Flag[] ALL = find(); + public String caption; + public int value; + + private Flag() { + } + + private static Flag[] find() { + List<Flag> flags = new ArrayList(); + String prefix = "SYSTEM_UI_FLAG_"; + for (Field f : View.class.getFields()) { + if (f.getName().startsWith(prefix)) { + Flag flag = new Flag(); + flag.caption = f.getName().substring(prefix.length()).replace("NAVIGATION", "NAV").replace("TRANSPARENT", "TRANSP").replace("LAYOUT", "LAY"); + try { + flag.value = f.getInt(null); + if (flag.value != 0) { + flags.add(flag); + } + } catch (Throwable t) { + RuntimeException runtimeException = new RuntimeException(t); + } + } + } + Collections.sort(flags); + return (Flag[]) flags.toArray(new Flag[flags.size()]); + } + + public int compareTo(Flag another) { + if (this.value < another.value) { + return -1; + } + return this.value > another.value ? 1 : 0; + } + } + + private class FlagCheckBox extends CheckBox { + private final Flag mFlag; + + public FlagCheckBox(Context context, Flag flag) { + super(context); + setText(flag.caption); + this.mFlag = flag; + } + } + + private class FlagSetButton extends Button { + public FlagSetButton(Context context) { + super(context); + setText("Set visibility"); + setOnClickListener(new OnClickListener() { + public void onClick(View v) { + FlagSetButton.this.set(); + } + }); + } + + private void set() { + ViewGroup parent = (ViewGroup) getParent(); + int n = parent.getChildCount(); + int vis = 0; + for (int i = 0; i < n; i++) { + View v = parent.getChildAt(i); + if (v instanceof FlagCheckBox) { + FlagCheckBox cb = (FlagCheckBox) v; + if (cb.isChecked()) { + vis |= cb.mFlag.value; + } + } + } + FitSystemWindowsActivity.this.update(vis); + } + } + + private class FlagStateTextView extends TextView { + public FlagStateTextView(Context context) { + super(context); + updateText(); + setOnClickListener(new OnClickListener() { + public void onClick(View v) { + FlagStateTextView.this.updateText(); + } + }); + } + + private void updateText() { + StringBuilder sb = new StringBuilder(); + append(sb, "vis", FitSystemWindowsActivity.this.mLayout.getSystemUiVisibility()); + append(sb, "win", getWindowSystemUiVisibility()); + setText(sb.toString()); + } + + private void append(StringBuilder sb, String caption, int vis) { + if (sb.length() > 0) { + sb.append('\n'); + } + sb.append(caption).append(':'); + boolean first = true; + for (Flag flag : Flag.ALL) { + if ((flag.value & vis) != 0) { + if (first) { + first = false; + } else { + sb.append(", "); + } + sb.append(flag.caption); + } + } + } + } + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.mLayout = new LinearLayout(this.mContext) { + protected boolean fitSystemWindows(Rect insets) { + Rect insetsBefore = new Rect(insets); + String msg = String.format("before=%s\nrt=%s\nafter=%s", new Object[]{insetsBefore.toShortString(), Boolean.valueOf(super.fitSystemWindows(insets)), insets.toShortString()}); + return super.fitSystemWindows(insets); + } + }; + this.mLayout.setOrientation(1); + for (Flag flag : Flag.ALL) { + this.mLayout.addView(new FlagCheckBox(this.mContext, flag)); + } + this.mLayout.addView(new FlagSetButton(this.mContext)); + LinearLayout linearLayout = this.mLayout; + View flagStateTextView = new FlagStateTextView(this.mContext); + this.mFlagStateTextView = (FlagStateTextView) flagStateTextView; + linearLayout.addView(flagStateTextView); + this.mLayout.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() { + public void onSystemUiVisibilityChange(int vis) { + FitSystemWindowsActivity.this.updateTextDelayed(); + } + }); + this.mLayout.setPadding(0, 146, 0, 0); + setContentView(this.mLayout); + } + + private void update(int vis) { + this.mLayout.setSystemUiVisibility(vis); + updateTextDelayed(); + } + + private void updateTextDelayed() { + this.mHandler.removeCallbacks(this.mUpdateText); + this.mHandler.postDelayed(this.mUpdateText, 500); + } +} diff --git a/KBars/app/src/main/java/js/kbars/IdentifyBarsButton.java b/KBars/app/src/main/java/js/kbars/IdentifyBarsButton.java new file mode 100644 index 0000000..18223d0 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/IdentifyBarsButton.java @@ -0,0 +1,21 @@ +package js.kbars; + +import android.content.Context; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; + +public class IdentifyBarsButton extends Button { + public IdentifyBarsButton(Context context) { + super(context); + setText("Identify system bars"); + setOnClickListener(new OnClickListener() { + public void onClick(View v) { + IdentifyBarsButton.this.identifyBars(); + } + }); + } + + private void identifyBars() { + } +} diff --git a/KBars/app/src/main/java/js/kbars/ImageBackgroundMenuItem.java b/KBars/app/src/main/java/js/kbars/ImageBackgroundMenuItem.java new file mode 100644 index 0000000..8052d9e --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/ImageBackgroundMenuItem.java @@ -0,0 +1,109 @@ +package js.kbars; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.net.Uri; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MenuItem.OnMenuItemClickListener; +import android.view.View; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +public final class ImageBackgroundMenuItem implements OnMenuItemClickListener { + public static final int REQUEST_CODE = 234; + private static final String TAG = ImageBackgroundMenuItem.class.getSimpleName(); + private final Activity mActivity; + private final View mTarget; + + public ImageBackgroundMenuItem(Menu menu, Activity activity, View target) { + this.mActivity = activity; + this.mTarget = target; + menu.add("Select image background...").setOnMenuItemClickListener(this); + loadBitmap(); + } + + public boolean onMenuItemClick(MenuItem item) { + chooseBackground(); + return true; + } + + public void onActivityResult(int resultCode, Intent data) { + if (resultCode == -1) { + Uri image = data.getData(); + try { + Bitmap bitmap = BitmapFactory.decodeStream(this.mActivity.getContentResolver().openInputStream(image)); + if (bitmap != null) { + setTargetBackground(bitmap); + saveBitmap(bitmap); + } + } catch (FileNotFoundException e) { + Log.w(TAG, "Error getting image " + image, e); + } + } + } + + private void chooseBackground() { + Intent photoPickerIntent = new Intent("android.intent.action.PICK"); + photoPickerIntent.setType("image/*"); + this.mActivity.startActivityForResult(photoPickerIntent, REQUEST_CODE); + } + + private File bitmapFile() { + return new File(this.mActivity.getCacheDir(), "background.png"); + } + + private void saveBitmap(Bitmap bitmap) { + FileNotFoundException e; + Throwable th; + File f = bitmapFile(); + if (f.exists()) { + f.delete(); + } + if (bitmap != null) { + try { + FileOutputStream out = new FileOutputStream(f); + bitmap.compress(CompressFormat.PNG, 100, out); + out.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + + private void loadBitmap() { + Bitmap bitmap = loadBitmapFromCache(); + if (bitmap == null) { + bitmap = loadBitmapFromAssets(); + } + setTargetBackground(bitmap); + } + + private Bitmap loadBitmapFromCache() { + File f = bitmapFile(); + return f.exists() ? BitmapFactory.decodeFile(f.getAbsolutePath()) : null; + } + + private Bitmap loadBitmapFromAssets() { + try { + return BitmapFactory.decodeStream(this.mActivity.getAssets().open("background.png")); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void setTargetBackground(Bitmap bitmap) { + if (bitmap == null) { + this.mTarget.setBackground(null); + } else { + this.mTarget.setBackground(new BitmapDrawable(this.mActivity.getResources(), bitmap)); + } + } +} diff --git a/KBars/app/src/main/java/js/kbars/ImmersiveModeToggleButton.java b/KBars/app/src/main/java/js/kbars/ImmersiveModeToggleButton.java new file mode 100644 index 0000000..a904b37 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/ImmersiveModeToggleButton.java @@ -0,0 +1,79 @@ +package js.kbars; + +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnSystemUiVisibilityChangeListener; +import android.widget.Button; + +public final class ImmersiveModeToggleButton extends Button { + private final KBarsActivity mActivity; + private final String mCaption; + private final int mImmersiveFlags; + private boolean mImmersiveMode; + + public ImmersiveModeToggleButton(KBarsActivity activity, String caption, int immersiveFlags) { + super(activity); + this.mActivity = activity; + this.mCaption = caption; + this.mImmersiveFlags = immersiveFlags; + setOnClickListener(new OnClickListener() { + public void onClick(View v) { + ImmersiveModeToggleButton.this.toggleImmersiveMode("clicked"); + } + }); + updateImmersiveModeButton(); + setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() { + public void onSystemUiVisibilityChange(int visibility) { + ImmersiveModeToggleButton.this.onSysuiChanged(visibility); + } + }); + } + + private void toggleImmersiveMode(String reason) { + boolean z; + boolean z2 = false; + Log.d(KBarsActivity.TAG, "toggleImmersiveMode reason=" + reason); + if (this.mImmersiveMode) { + z = false; + } else { + z = true; + } + this.mImmersiveMode = z; + updateImmersiveModeButton(); + KBarsActivity kBarsActivity = this.mActivity; + if (!this.mImmersiveMode) { + z2 = true; + } + kBarsActivity.setSoloButton(z2, this, true); + } + + private void updateImmersiveModeButton() { + Log.d(KBarsActivity.TAG, "updateButtons mImmersiveMode=" + this.mImmersiveMode); + setText(this.mImmersiveMode ? "Exit " + this.mCaption + " mode" : "Enter " + this.mCaption + " mode"); + setSystemUiVisibility(this.mImmersiveMode ? this.mImmersiveFlags : KBarsActivity.BASE_FLAGS); + } + + private void onSysuiChanged(int vis) { + boolean hideStatus; + boolean hideSomething = false; + Log.d(KBarsActivity.TAG, "sysui changed: " + Integer.toHexString(vis)); + if ((vis & 4) != 0) { + hideStatus = true; + } else { + hideStatus = false; + } + boolean hideNav; + if ((vis & 2) != 0) { + hideNav = true; + } else { + hideNav = false; + } + if (hideStatus || hideNav) { + hideSomething = true; + } + if (this.mImmersiveMode && !hideSomething) { + toggleImmersiveMode("sysui_changed"); + } + } +} diff --git a/KBars/app/src/main/java/js/kbars/KBarsActivity.java b/KBars/app/src/main/java/js/kbars/KBarsActivity.java new file mode 100644 index 0000000..33733ac --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/KBarsActivity.java @@ -0,0 +1,273 @@ +package js.kbars; + +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.os.Handler; +import android.util.DisplayMetrics; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MenuItem.OnMenuItemClickListener; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.Window; +import android.widget.Button; +import android.widget.EditText; +import android.widget.FrameLayout.LayoutParams; +import android.widget.LinearLayout; +import android.widget.Toast; +import java.util.ArrayList; +import java.util.List; + +public class KBarsActivity extends Activity { + public static final int BASE_FLAGS = 1792; + static final boolean DEBUG = true; + public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; + public static final int FLAG_TRANSLUCENT_STATUS = 67108864; + private static final int IMMERSIVE_FLAGS = 3846; + private static final int IMMERSIVE_FLAGS_STICKY = 5894; + private static final int SYSTEM_UI_FLAG_IMMERSIVE = 2048; + private static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 4096; + static final String TAG = Util.logTag(KBarsActivity.class); + private List<View> mButtons = new ArrayList(); + private CameraBackgroundMenuItem mCameraBackgroundMenuItem; + private final Context mContext = this; + private EditText mEditText; + private TouchTrackingLayout mFrame; + private ImageBackgroundMenuItem mImageBackgroundMenuItem; + + private static final class DebugButton extends Button { + private final Handler mHandler = new Handler(); + private final Runnable mNavTransOff = new Runnable() { + public void run() { + DebugButton.this.setNavTrans(false); + } + }; + private final Runnable mNavTransOn = new Runnable() { + public void run() { + DebugButton.this.setNavTrans(true); + DebugButton.this.cancelTrans(); + DebugButton.this.mHandler.postDelayed(DebugButton.this.mNavTransOff, 5000); + } + }; + + public DebugButton(Context context) { + super(context); + setText("Debug"); + setOnClickListener(new OnClickListener() { + public void onClick(View v) { + DebugButton.this.fallingToast(); + } + }); + } + + private void cancelTrans() { + this.mHandler.removeCallbacks(this.mNavTransOn); + this.mHandler.removeCallbacks(this.mNavTransOff); + } + + private void setNavTrans(boolean trans) { + Window w = ((Activity) getContext()).getWindow(); + if (trans) { + w.addFlags(KBarsActivity.FLAG_TRANSLUCENT_STATUS); + } else { + w.clearFlags(KBarsActivity.FLAG_TRANSLUCENT_STATUS); + } + } + + public void fallingToast() { + this.mNavTransOff.run(); + Toast.makeText(getContext(), "Here is a toast", 1).show(); + cancelTrans(); + this.mHandler.postDelayed(this.mNavTransOn, 1000); + } + } + + private static final class InvisibleButton extends Button { + public InvisibleButton(Context context) { + super(context); + super.setVisibility(4); + } + + public void setVisibility(int visibility) { + } + } + + protected void onCreate(Bundle savedInstanceState) { + boolean portrait; + int i = 0; + super.onCreate(savedInstanceState); + getWindow().requestFeature(9); + DisplayMetrics dm = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getRealMetrics(dm); + Toast.makeText(this.mContext, dm.widthPixels + "x" + dm.heightPixels + " supported=" + areTranslucentBarsSupported(), 0).show(); + getActionBar().setTitle("kbars " + Util.getVersionName(this.mContext)); + getActionBar().setBackgroundDrawable(new ColorDrawable(0)); + this.mFrame = new TouchTrackingLayout(this.mContext); + LinearLayout allButtons = new LinearLayout(this.mContext); + Configuration config = getResources().getConfiguration(); + if (((float) config.screenWidthDp) / ((float) config.screenHeightDp) < 1.0f) { + portrait = true; + } else { + portrait = false; + } + if (portrait) { + i = 1; + } + allButtons.setOrientation(i); + LinearLayout buttons1 = new LinearLayout(this.mContext); + buttons1.setOrientation(1); + LinearLayout buttons2 = new LinearLayout(this.mContext); + buttons2.setOrientation(1); + allButtons.addView(buttons1); + allButtons.addView(buttons2); + LayoutParams buttonsLP = new LayoutParams(-2, -2); + buttonsLP.gravity = 17; + this.mFrame.addView(allButtons, buttonsLP); + this.mEditText = new EditText(this.mContext); + this.mEditText.setVisibility(8); + buttons1.addView(this.mEditText, -1, -2); + buttons1.addView(new TransparencyToggleButton(this.mContext, "status bar", FLAG_TRANSLUCENT_STATUS)); + buttons1.addView(new TransparencyToggleButton(this.mContext, "navigation bar", FLAG_TRANSLUCENT_NAVIGATION)); + buttons1.addView(new InvisibleButton(this.mContext)); + buttons2.addView(new ImmersiveModeToggleButton(this, "immersive", IMMERSIVE_FLAGS)); + buttons2.addView(new ImmersiveModeToggleButton(this, "sticky immersive", IMMERSIVE_FLAGS_STICKY)); + buttons2.addView(new LightsOutModeToggleButton(this.mContext)); + buttons2.addView(new MediaModeToggleButton(this.mContext, this.mFrame)); + buttons2.addView(new InvisibleButton(this.mContext)); + setContentView(this.mFrame); + addButtons(buttons1); + addButtons(buttons2); + } + + private void addButtons(LinearLayout buttons) { + for (int i = 0; i < buttons.getChildCount(); i++) { + this.mButtons.add(buttons.getChildAt(i)); + } + } + + private boolean areTranslucentBarsSupported() { + int id = getResources().getIdentifier("config_enableTranslucentDecor", "bool", "android"); + if (id == 0) { + return false; + } + return getResources().getBoolean(id); + } + + public boolean onCreateOptionsMenu(Menu menu) { + RandomColorBackgroundMenuItem randomColorBackgroundMenuItem = new RandomColorBackgroundMenuItem(menu, this.mFrame); + this.mImageBackgroundMenuItem = new ImageBackgroundMenuItem(menu, this, this.mFrame); + this.mCameraBackgroundMenuItem = new CameraBackgroundMenuItem(menu, this, this.mFrame); + createDebugMenuItem(menu); + createEditTextMenuItem(menu); + createOrientationMenuItem(menu, R.string.action_portrait, 1); + createOrientationMenuItem(menu, R.string.action_landscape, 0); + createOrientationMenuItem(menu, R.string.action_reverse_portrait, 9); + createOrientationMenuItem(menu, R.string.action_reverse_landscape, 8); + return true; + } + + private void createOrientationMenuItem(Menu menu, int text, final int orientation) { + MenuItem mi = menu.add(text); + mi.setShowAsAction(0); + mi.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + KBarsActivity.this.setRequestedOrientation(orientation); + return true; + } + }); + } + + private void createDebugMenuItem(Menu menu) { + final MenuItem mi = menu.add("Show gesture debugging"); + mi.setShowAsActionFlags(0); + mi.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + boolean debug; + if (KBarsActivity.this.mFrame.getDebug()) { + debug = false; + } else { + debug = true; + } + KBarsActivity.this.mFrame.setDebug(debug); + mi.setTitle(new StringBuilder(String.valueOf(debug ? "Hide" : "Show")).append(" gesture debugging").toString()); + return true; + } + }); + } + + private void createEditTextMenuItem(Menu menu) { + final MenuItem mi = menu.add("Show EditText"); + mi.setShowAsActionFlags(0); + mi.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + boolean isVisible; + int i = 0; + if (KBarsActivity.this.mEditText.getVisibility() == 0) { + isVisible = true; + } else { + isVisible = false; + } + EditText access$1 = KBarsActivity.this.mEditText; + if (isVisible) { + i = 8; + } + access$1.setVisibility(i); + mi.setTitle(new StringBuilder(String.valueOf(isVisible ? "Show" : "Hide")).append(" EditText").toString()); + return true; + } + }); + } + + public void setSoloButton(boolean visible, View solo, boolean animate) { + int i; + int vis = 0; + if (visible) { + i = 1; + } else { + i = 0; + } + float alpha = (float) i; + if (!visible) { + vis = 4; + } + final int _vis = vis; + for (final View view : this.mButtons) { + if (!(view == solo || (view instanceof EditText))) { + view.setEnabled(visible); + if (animate) { + view.animate().alpha(alpha).setListener(new AnimatorListener() { + public void onAnimationCancel(Animator animation) { + } + + public void onAnimationEnd(Animator animation) { + view.setVisibility(_vis); + } + + public void onAnimationRepeat(Animator animation) { + } + + public void onAnimationStart(Animator animation) { + } + }).start(); + } else { + view.setVisibility(vis); + } + } + } + } + + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == CameraBackgroundMenuItem.REQUEST_CODE) { + this.mCameraBackgroundMenuItem.onActivityResult(resultCode, data); + } + if (requestCode == ImageBackgroundMenuItem.REQUEST_CODE) { + this.mImageBackgroundMenuItem.onActivityResult(resultCode, data); + } + } +} diff --git a/KBars/app/src/main/java/js/kbars/KBarsCar.java b/KBars/app/src/main/java/js/kbars/KBarsCar.java new file mode 100644 index 0000000..c280c95 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/KBarsCar.java @@ -0,0 +1,38 @@ +package js.kbars; + +import android.app.Activity; +import android.app.UiModeManager; +import android.content.Context; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; + +public class KBarsCar extends Activity { + private static final String TAG = Util.logTag(KBarsCar.class); + private final Context mContext = this; + private View mView; + + protected void onCreate(Bundle savedInstanceState) { + requestWindowFeature(1); + super.onCreate(savedInstanceState); + this.mView = new View(this.mContext); + this.mView.setBackgroundColor(-65536); + setFullscreen(); + setContentView(this.mView); + this.mView.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + ((UiModeManager) KBarsCar.this.mContext.getSystemService("uimode")).disableCarMode(1); + KBarsCar.this.finish(); + } + }); + } + + protected void onResume() { + super.onResume(); + setFullscreen(); + } + + private void setFullscreen() { + this.mView.setSystemUiVisibility(5382); + } +} diff --git a/KBars/app/src/main/java/js/kbars/KBarsDream.java b/KBars/app/src/main/java/js/kbars/KBarsDream.java new file mode 100644 index 0000000..7a4c92b --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/KBarsDream.java @@ -0,0 +1,47 @@ +package js.kbars; + +import android.content.Context; +import android.os.Handler; +import android.service.dreams.DreamService; +import android.util.Log; +import android.view.View; +import android.view.View.OnSystemUiVisibilityChangeListener; + +public class KBarsDream extends DreamService { + private static final String TAG = Util.logTag(KBarsDream.class); + private final Context mContext = this; + private final Handler mHandler = new Handler(); + private View mView; + + public void onCreate() { + super.onCreate(); + setInteractive(true); + } + + public void onAttachedToWindow() { + super.onAttachedToWindow(); + this.mView = new View(this.mContext); + getWindow().addFlags(1024); + setFullscreen(); + this.mView.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() { + public void onSystemUiVisibilityChange(int visibility) { + Log.d(KBarsDream.TAG, "onSystemUiVisibilityChange " + Integer.toHexString(visibility)); + KBarsDream.this.setFullscreen(); + } + }); + this.mView.setBackgroundColor(-16776961); + setContentView(this.mView); + } + + public void onWindowFocusChanged(boolean hasFocus) { + Log.d(TAG, "onWindowFocusChanged " + hasFocus); + super.onWindowFocusChanged(hasFocus); + if (hasFocus) { + setFullscreen(); + } + } + + private void setFullscreen() { + this.mView.setSystemUiVisibility(5382); + } +} diff --git a/KBars/app/src/main/java/js/kbars/LightsOutModeToggleButton.java b/KBars/app/src/main/java/js/kbars/LightsOutModeToggleButton.java new file mode 100644 index 0000000..9593142 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/LightsOutModeToggleButton.java @@ -0,0 +1,26 @@ +package js.kbars; + +import android.content.Context; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; + +public final class LightsOutModeToggleButton extends Button { + private boolean mLightsOut; + + public LightsOutModeToggleButton(Context context) { + super(context); + setOnClickListener(new OnClickListener() { + public void onClick(View v) { + LightsOutModeToggleButton.this.mLightsOut = !LightsOutModeToggleButton.this.mLightsOut; + LightsOutModeToggleButton.this.update(); + } + }); + update(); + } + + private void update() { + setText(new StringBuilder(String.valueOf(this.mLightsOut ? "Exit" : "Enter")).append(" lights out mode").toString()); + setSystemUiVisibility(this.mLightsOut ? 1 : 0); + } +} diff --git a/KBars/app/src/main/java/js/kbars/MediaModeToggleButton.java b/KBars/app/src/main/java/js/kbars/MediaModeToggleButton.java new file mode 100644 index 0000000..1e2b19d --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/MediaModeToggleButton.java @@ -0,0 +1,95 @@ +package js.kbars; + +import android.content.Context; +import android.media.MediaPlayer; +import android.media.MediaPlayer.OnPreparedListener; +import android.net.Uri; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnSystemUiVisibilityChangeListener; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.FrameLayout.LayoutParams; +import android.widget.VideoView; + +public final class MediaModeToggleButton extends Button { + private static final int MEDIA_FLAGS = 1798; + private final FrameLayout mFrame; + private boolean mMediaMode; + private VideoView mVideo; + + public MediaModeToggleButton(Context context, FrameLayout frame) { + super(context); + this.mFrame = frame; + setText("Enter media mode"); + setOnClickListener(new OnClickListener() { + public void onClick(View v) { + MediaModeToggleButton.this.setSystemUiVisibility(MediaModeToggleButton.MEDIA_FLAGS); + } + }); + setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() { + public void onSystemUiVisibilityChange(int vis) { + MediaModeToggleButton.this.updateSysUi(vis); + } + }); + initVideo(); + updateSysUi(0); + } + + private void initVideo() { + this.mVideo = new VideoView(getContext()); + this.mVideo.setVisibility(8); + LayoutParams videoLP = new LayoutParams(-1, -1); + videoLP.gravity = 17; + this.mFrame.addView(this.mVideo, videoLP); + this.mVideo.setOnPreparedListener(new OnPreparedListener() { + public void onPrepared(MediaPlayer mp) { + mp.setLooping(true); + } + }); + this.mVideo.setVideoURI(Uri.parse("android.resource://" + getContext().getPackageName() + "/" + R.raw.clipcanvas)); + this.mVideo.setBackgroundColor(0); + } + + private void updateSysUi(int vis) { + boolean requested; + boolean hideStatus; + boolean hideNav; + boolean hideSomething; + if (getSystemUiVisibility() == MEDIA_FLAGS) { + requested = true; + } else { + requested = false; + } + if ((vis & 4) != 0) { + hideStatus = true; + } else { + hideStatus = false; + } + if ((vis & 2) != 0) { + hideNav = true; + } else { + hideNav = false; + } + if (hideStatus || hideNav) { + hideSomething = true; + } else { + hideSomething = false; + } + Log.d(KBarsActivity.TAG, String.format("vis change hideStatus=%s hideNav=%s hideSomething=%s mMediaMode=%s", new Object[]{Boolean.valueOf(hideStatus), Boolean.valueOf(hideNav), Boolean.valueOf(hideSomething), Boolean.valueOf(this.mMediaMode)})); + this.mMediaMode = false; + if (requested && hideStatus && hideNav) { + this.mMediaMode = true; + } else { + setSystemUiVisibility(KBarsActivity.BASE_FLAGS); + } + if (this.mMediaMode) { + this.mVideo.setVisibility(0); + this.mVideo.start(); + return; + } + this.mVideo.setVisibility(8); + this.mVideo.stopPlayback(); + } +} diff --git a/KBars/app/src/main/java/js/kbars/RandomColorBackgroundMenuItem.java b/KBars/app/src/main/java/js/kbars/RandomColorBackgroundMenuItem.java new file mode 100644 index 0000000..d1895f3 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/RandomColorBackgroundMenuItem.java @@ -0,0 +1,29 @@ +package js.kbars; + +import android.graphics.Color; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MenuItem.OnMenuItemClickListener; +import android.view.View; +import java.util.Random; + +public class RandomColorBackgroundMenuItem implements OnMenuItemClickListener { + private static final Random RANDOM = new Random(); + private final View mTarget; + + public RandomColorBackgroundMenuItem(Menu menu, View target) { + this.mTarget = target; + MenuItem mi = menu.add("Random color background"); + mi.setShowAsActionFlags(0); + mi.setOnMenuItemClickListener(this); + } + + private void setColorBackground() { + this.mTarget.setBackgroundColor(Color.rgb(RANDOM.nextInt(255), RANDOM.nextInt(255), RANDOM.nextInt(255))); + } + + public boolean onMenuItemClick(MenuItem item) { + setColorBackground(); + return true; + } +} diff --git a/KBars/app/src/main/java/js/kbars/SystemGestureDebugger.java b/KBars/app/src/main/java/js/kbars/SystemGestureDebugger.java new file mode 100644 index 0000000..3992a82 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/SystemGestureDebugger.java @@ -0,0 +1,216 @@ +package js.kbars; + +import android.content.Context; +import android.util.Log; +import android.view.MotionEvent; + +public class SystemGestureDebugger { + private static final boolean DEBUG = false; + private static final int MAX_TRACKED_POINTERS = 32; + private static final int SWIPE_FROM_BOTTOM = 2; + private static final int SWIPE_FROM_RIGHT = 3; + private static final int SWIPE_FROM_TOP = 1; + private static final int SWIPE_NONE = 0; + private static final long SWIPE_TIMEOUT_MS = 500; + private static final String TAG = Util.logTag(SystemGestureDebugger.class); + private static final int UNTRACKED_POINTER = -1; + private final Callbacks mCallbacks; + private final float[] mCurrentX = new float[MAX_TRACKED_POINTERS]; + private final float[] mCurrentY = new float[MAX_TRACKED_POINTERS]; + private boolean mDebugFireable; + private final int[] mDownPointerId = new int[MAX_TRACKED_POINTERS]; + private int mDownPointers; + private final long[] mDownTime = new long[MAX_TRACKED_POINTERS]; + private final float[] mDownX = new float[MAX_TRACKED_POINTERS]; + private final float[] mDownY = new float[MAX_TRACKED_POINTERS]; + private final long[] mElapsedThreshold = new long[MAX_TRACKED_POINTERS]; + private final int mSwipeDistanceThreshold; + private boolean mSwipeFireable; + private final int mSwipeStartThreshold; + int screenHeight; + int screenWidth; + + interface Callbacks { + void onDebug(); + + void onSwipeFromBottom(); + + void onSwipeFromRight(); + + void onSwipeFromTop(); + } + + public static class DownPointerInfo { + public float currentX; + public float currentY; + public int downPointerId; + public long downTime; + public float downX; + public float downY; + public long elapsedThreshold; + } + + public static class ThresholdInfo { + public int distance; + public long elapsed; + public int start; + } + + public SystemGestureDebugger(Context context, Callbacks callbacks) { + this.mCallbacks = (Callbacks) checkNull("callbacks", callbacks); + this.mSwipeStartThreshold = ((Context) checkNull("context", context)).getResources().getDimensionPixelSize(((Integer) Util.getField("com.android.internal.R$dimen", "status_bar_height")).intValue()); + this.mSwipeDistanceThreshold = this.mSwipeStartThreshold; + Log.d(TAG, String.format("startThreshold=%s endThreshold=%s", new Object[]{Integer.valueOf(this.mSwipeStartThreshold), Integer.valueOf(this.mSwipeDistanceThreshold)})); + } + + private static <T> T checkNull(String name, T arg) { + if (arg != null) { + return arg; + } + throw new IllegalArgumentException(new StringBuilder(String.valueOf(name)).append(" must not be null").toString()); + } + + public void onPointerEvent(MotionEvent event) { + boolean z = true; + boolean z2 = DEBUG; + switch (event.getActionMasked()) { + case SWIPE_NONE /*0*/: + this.mSwipeFireable = true; + this.mDebugFireable = true; + this.mDownPointers = SWIPE_NONE; + captureDown(event, SWIPE_NONE); + return; + case 1: + case SWIPE_FROM_RIGHT /*3*/: + this.mSwipeFireable = DEBUG; + this.mDebugFireable = DEBUG; + return; + case 2: + if (this.mSwipeFireable) { + int swipe = detectSwipe(event); + if (swipe == 0) { + z2 = true; + } + this.mSwipeFireable = z2; + if (swipe == 1) { + this.mCallbacks.onSwipeFromTop(); + return; + } else if (swipe == 2) { + this.mCallbacks.onSwipeFromBottom(); + return; + } else if (swipe == SWIPE_FROM_RIGHT) { + this.mCallbacks.onSwipeFromRight(); + return; + } else { + return; + } + } + return; + case 5: + captureDown(event, event.getActionIndex()); + if (this.mDebugFireable) { + if (event.getPointerCount() >= 5) { + z = DEBUG; + } + this.mDebugFireable = z; + if (!this.mDebugFireable) { + this.mCallbacks.onDebug(); + return; + } + return; + } + return; + default: + return; + } + } + + private void captureDown(MotionEvent event, int pointerIndex) { + int i = findIndex(event.getPointerId(pointerIndex)); + if (i != UNTRACKED_POINTER) { + this.mDownX[i] = event.getX(pointerIndex); + this.mDownY[i] = event.getY(pointerIndex); + this.mDownTime[i] = event.getEventTime(); + } + } + + private int findIndex(int pointerId) { + for (int i = SWIPE_NONE; i < this.mDownPointers; i++) { + if (this.mDownPointerId[i] == pointerId) { + return i; + } + } + if (this.mDownPointers == MAX_TRACKED_POINTERS || pointerId == UNTRACKED_POINTER) { + return UNTRACKED_POINTER; + } + int[] iArr = this.mDownPointerId; + int i2 = this.mDownPointers; + this.mDownPointers = i2 + 1; + iArr[i2] = pointerId; + return this.mDownPointers + UNTRACKED_POINTER; + } + + private int detectSwipe(MotionEvent move) { + int historySize = move.getHistorySize(); + int pointerCount = move.getPointerCount(); + for (int p = SWIPE_NONE; p < pointerCount; p++) { + int i = findIndex(move.getPointerId(p)); + if (i != UNTRACKED_POINTER) { + int swipe; + for (int h = SWIPE_NONE; h < historySize; h++) { + swipe = detectSwipe(i, move.getHistoricalEventTime(h), move.getHistoricalX(p, h), move.getHistoricalY(p, h)); + if (swipe != 0) { + return swipe; + } + } + swipe = detectSwipe(i, move.getEventTime(), move.getX(p), move.getY(p)); + if (swipe != 0) { + return swipe; + } + } + } + return SWIPE_NONE; + } + + private int detectSwipe(int i, long time, float x, float y) { + float fromX = this.mDownX[i]; + float fromY = this.mDownY[i]; + long elapsed = time - this.mDownTime[i]; + this.mCurrentX[i] = x; + this.mCurrentY[i] = y; + boolean reachedThreshold = ((fromY > ((float) this.mSwipeStartThreshold) || y <= ((float) this.mSwipeDistanceThreshold) + fromY) && ((fromY < ((float) (this.screenHeight - this.mSwipeStartThreshold)) || y >= fromY - ((float) this.mSwipeDistanceThreshold)) && (fromX < ((float) (this.screenWidth - this.mSwipeStartThreshold)) || x >= fromX - ((float) this.mSwipeDistanceThreshold)))) ? DEBUG : true; + if (!reachedThreshold) { + this.mElapsedThreshold[i] = elapsed; + } + if (fromY <= ((float) this.mSwipeStartThreshold) && y > ((float) this.mSwipeDistanceThreshold) + fromY && elapsed < SWIPE_TIMEOUT_MS) { + return 1; + } + if (fromY >= ((float) (this.screenHeight - this.mSwipeStartThreshold)) && y < fromY - ((float) this.mSwipeDistanceThreshold) && elapsed < SWIPE_TIMEOUT_MS) { + return 2; + } + if (fromX < ((float) (this.screenWidth - this.mSwipeStartThreshold)) || x >= fromX - ((float) this.mSwipeDistanceThreshold) || elapsed >= SWIPE_TIMEOUT_MS) { + return SWIPE_NONE; + } + return SWIPE_FROM_RIGHT; + } + + public int getDownPointers() { + return this.mDownPointers; + } + + public void getDownPointerInfo(int index, DownPointerInfo out) { + out.downPointerId = this.mDownPointerId[index]; + out.downX = this.mDownX[index]; + out.downY = this.mDownY[index]; + out.downTime = this.mDownTime[index]; + out.currentX = this.mCurrentX[index]; + out.currentY = this.mCurrentY[index]; + out.elapsedThreshold = this.mElapsedThreshold[index]; + } + + public void getThresholdInfo(ThresholdInfo out) { + out.start = this.mSwipeStartThreshold; + out.distance = this.mSwipeDistanceThreshold; + out.elapsed = SWIPE_TIMEOUT_MS; + } +} diff --git a/KBars/app/src/main/java/js/kbars/ToastActivity.java b/KBars/app/src/main/java/js/kbars/ToastActivity.java new file mode 100644 index 0000000..18f9a89 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/ToastActivity.java @@ -0,0 +1,117 @@ +package js.kbars; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Rect; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnSystemUiVisibilityChangeListener; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +public class ToastActivity extends Activity { + private static final int ALLOW_TRANSIENT = 2048; + private static final String TAG = Util.logTag(ToastActivity.class); + private View mContent; + private final Context mContext = this; + boolean mImmersive; + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LinearLayout buttons = new LinearLayout(this.mContext); + buttons.setOrientation(1); + for (final Method m : getClass().getDeclaredMethods()) { + if (Modifier.isPublic(m.getModifiers()) && m.getParameterTypes().length == 0) { + Button btn = new Button(this.mContext); + btn.setText(m.getName()); + btn.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + try { + m.invoke(ToastActivity.this.mContext, new Object[0]); + } catch (Throwable t) { + Log.w(ToastActivity.TAG, "Error running " + m.getName(), t); + } + } + }); + buttons.addView(btn); + } + } + setContentView(buttons); + this.mContent = buttons; + setSysui(); + this.mContent.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() { + public void onSystemUiVisibilityChange(int visibility) { + if ((visibility & 2) == 0) { + ToastActivity.this.mImmersive = false; + ToastActivity.this.setSysui(); + } + } + }); + } + + public void toast1() { + Toast.makeText(this.mContext, "toast!", 0).show(); + } + + public void toast2() { + Toast t = Toast.makeText(this.mContext, "toast!", 0); + TextView tv = new TextView(this.mContext); + tv.setBackgroundColor(-65536); + tv.setText("setView"); + t.setView(tv); + t.show(); + } + + public void toast3() { + Toast t = Toast.makeText(this.mContext, "toast!", 0); + TextView tv = new TextView(this.mContext) { + protected boolean fitSystemWindows(Rect insets) { + Rect before = new Rect(insets); + boolean rt = super.fitSystemWindows(insets); + Log.d(ToastActivity.TAG, String.format("before=%s rt=%s after=%s", new Object[]{before.toShortString(), Boolean.valueOf(rt), insets.toShortString()})); + return rt; + } + }; + Log.d(TAG, "fitsSystemWindows=" + tv.getFitsSystemWindows()); + tv.setFitsSystemWindows(true); + tv.setSystemUiVisibility(768); + tv.setBackgroundColor(-65536); + tv.setText("setView"); + t.setView(tv); + t.show(); + } + + public void hideNav() { + this.mContent.setSystemUiVisibility(2); + } + + public void dangerToast() { + Toast t = Toast.makeText(this.mContext, "toast!", 0); + TextView tv = new TextView(this.mContext); + tv.setSystemUiVisibility(512); + tv.setBackgroundColor(-65536); + tv.setText("setView"); + t.setView(tv); + t.setGravity(80, 0, 90); + t.show(); + } + + public void toggleImmersive() { + this.mImmersive = !this.mImmersive; + setSysui(); + } + + private void setSysui() { + int flags = 2560; + if (this.mImmersive) { + flags = 2560 | 2; + } + this.mContent.setSystemUiVisibility(flags); + } +} diff --git a/KBars/app/src/main/java/js/kbars/TouchTrackingLayout.java b/KBars/app/src/main/java/js/kbars/TouchTrackingLayout.java new file mode 100644 index 0000000..83e6c30 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/TouchTrackingLayout.java @@ -0,0 +1,298 @@ +package js.kbars; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.Cap; +import android.graphics.Paint.Style; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnLayoutChangeListener; +import android.widget.FrameLayout; +import java.util.ArrayList; +import java.util.List; +import js.kbars.SystemGestureDebugger.DownPointerInfo; +import js.kbars.SystemGestureDebugger.ThresholdInfo; + +public class TouchTrackingLayout extends FrameLayout { + private static final boolean DEBUG_EVENTS = true; + private static final int MAX_INFO_LINES = 6; + private static final int MAX_POINTERS = 5; + private static final int MAX_POINTS = 5000; + private static final String TAG = Util.logTag(TouchTrackingLayout.class); + private boolean mDebug; + private final DownPointerInfo mDownPointerInfo = new DownPointerInfo(); + private final SystemGestureDebugger mGestures; + private final Paint mInfoPaint = new Paint(); + private final StringBuilder[] mInfoText = allocateInfoText(); + private final int mInfoTextLineHeight; + private final int mInfoTextOffset; + private final int[] mScribbleCounts = new int[MAX_POINTERS]; + private final Paint mScribblePaint = new Paint(); + private final List<float[]> mScribblePoints = allocatePoints(); + private final int mTextSize; + private final ThresholdInfo mThresholdInfo = new ThresholdInfo(); + private final float[] mThresholdLines = new float[16]; + private final Paint mThresholdPaint = new Paint(); + + public TouchTrackingLayout(Context context) { + super(context); + setWillNotDraw(false); + int densityDpi = Util.getDensityDpi(context); + this.mTextSize = (int) (((float) densityDpi) / 12.0f); + this.mInfoTextLineHeight = (int) (((float) densityDpi) / 11.0f); + this.mInfoTextOffset = (int) (((float) densityDpi) / 1.7f); + Log.d(TAG, "mTextSize=" + this.mTextSize + " mInfoTextLineHeight=" + this.mInfoTextLineHeight + " mInfoTextOffset=" + this.mInfoTextOffset); + this.mScribblePaint.setColor(-13388315); + this.mScribblePaint.setStrokeWidth((float) this.mTextSize); + this.mScribblePaint.setStrokeCap(Cap.ROUND); + this.mScribblePaint.setStyle(Style.STROKE); + this.mGestures = new SystemGestureDebugger(context, new SystemGestureDebugger.Callbacks() { + public void onSwipeFromTop() { + Log.d(TouchTrackingLayout.TAG, "GestureCallbacks.onSwipeFromTop"); + } + + public void onSwipeFromRight() { + Log.d(TouchTrackingLayout.TAG, "GestureCallbacks.onSwipeFromRight"); + } + + public void onSwipeFromBottom() { + Log.d(TouchTrackingLayout.TAG, "GestureCallbacks.onSwipeFromBottom"); + } + + public void onDebug() { + Log.d(TouchTrackingLayout.TAG, "GestureCallbacks.onDebug"); + } + }); + this.mGestures.getThresholdInfo(this.mThresholdInfo); + this.mInfoPaint.setTypeface(Typeface.MONOSPACE); + this.mInfoPaint.setTextSize((float) this.mTextSize); + this.mInfoPaint.setStyle(Style.STROKE); + this.mInfoPaint.setColor(-13388315); + this.mThresholdPaint.setColor(-13388315); + this.mThresholdPaint.setStrokeWidth(1.0f); + this.mThresholdPaint.setStyle(Style.STROKE); + addOnLayoutChangeListener(new OnLayoutChangeListener() { + public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { + TouchTrackingLayout.this.mGestures.screenWidth = right - left; + TouchTrackingLayout.this.mGestures.screenHeight = bottom - top; + TouchTrackingLayout.this.horLine(0, TouchTrackingLayout.this.mThresholdInfo.start); + TouchTrackingLayout.this.horLine(1, TouchTrackingLayout.this.mGestures.screenHeight - TouchTrackingLayout.this.mThresholdInfo.start); + TouchTrackingLayout.this.verLine(2, TouchTrackingLayout.this.mThresholdInfo.start); + TouchTrackingLayout.this.verLine(3, TouchTrackingLayout.this.mGestures.screenWidth - TouchTrackingLayout.this.mThresholdInfo.start); + } + }); + } + + public boolean getDebug() { + return this.mDebug; + } + + public void setDebug(boolean debug) { + this.mDebug = debug; + invalidate(); + } + + protected boolean fitSystemWindows(Rect insets) { + Rect insetsBefore = new Rect(insets); + boolean rt = super.fitSystemWindows(insets); + Log.d(TAG, String.format("fitSystemWindows insetsBefore=%s insetsAfter=%s rt=%s", new Object[]{insetsBefore.toShortString(), insets.toShortString(), Boolean.valueOf(rt)})); + return rt; + } + + private void horLine(int lineNum, int y) { + this.mThresholdLines[(lineNum * 4) + 0] = 0.0f; + float[] fArr = this.mThresholdLines; + int i = (lineNum * 4) + 1; + float f = (float) y; + this.mThresholdLines[(lineNum * 4) + 3] = f; + fArr[i] = f; + this.mThresholdLines[(lineNum * 4) + 2] = (float) this.mGestures.screenWidth; + } + + private void verLine(int lineNum, int x) { + float[] fArr = this.mThresholdLines; + int i = (lineNum * 4) + 0; + float f = (float) x; + this.mThresholdLines[(lineNum * 4) + 2] = f; + fArr[i] = f; + this.mThresholdLines[(lineNum * 4) + 1] = 0.0f; + this.mThresholdLines[(lineNum * 4) + 3] = (float) this.mGestures.screenHeight; + } + + private static StringBuilder[] allocateInfoText() { + StringBuilder[] rt = new StringBuilder[MAX_INFO_LINES]; + for (int i = 0; i < rt.length; i++) { + rt[i] = new StringBuilder(); + } + return rt; + } + + public boolean onTouchEvent(MotionEvent ev) { + super.onTouchEvent(ev); + this.mGestures.onPointerEvent(ev); + computeInfoText(); + onMotionEvent(ev); + return true; + } + + protected void onDraw(Canvas canvas) { + int i; + for (i = 0; i < this.mScribbleCounts.length; i++) { + int c = this.mScribbleCounts[i]; + if (c > 0) { + canvas.drawLines((float[]) this.mScribblePoints.get(i), 0, c - 2, this.mScribblePaint); + } + } + if (this.mDebug) { + int leftMargin = this.mThresholdInfo.start + (this.mTextSize / 4); + for (i = 0; i < this.mInfoText.length; i++) { + StringBuilder sb = this.mInfoText[i]; + canvas.drawText(sb, 0, sb.length(), (float) leftMargin, (float) (this.mInfoTextOffset + (this.mInfoTextLineHeight * i)), this.mInfoPaint); + } + canvas.drawLines(this.mThresholdLines, this.mThresholdPaint); + } + } + + private void computeInfoText() { + int dpc = this.mGestures.getDownPointers(); + for (int i = 0; i < this.mInfoText.length; i++) { + StringBuilder sb = this.mInfoText[i]; + sb.delete(0, sb.length()); + if (i == 0) { + sb.append("th "); + pad(sb, 9, this.mThresholdInfo.start); + sb.append(" "); + pad(sb, 9, this.mThresholdInfo.distance); + sb.append(' '); + pad(sb, MAX_POINTERS, (int) this.mThresholdInfo.elapsed); + sb.append("ms"); + } else if (i - 1 < dpc) { + this.mGestures.getDownPointerInfo(i - 1, this.mDownPointerInfo); + sb.append('p'); + sb.append(this.mDownPointerInfo.downPointerId); + sb.append(' '); + sb.append('('); + pad(sb, 4, (int) this.mDownPointerInfo.downX); + sb.append(','); + pad(sb, 4, (int) this.mDownPointerInfo.downY); + sb.append(')'); + sb.append(' '); + sb.append('('); + pad(sb, 4, (int) (this.mDownPointerInfo.currentX - this.mDownPointerInfo.downX)); + sb.append(','); + pad(sb, 4, (int) (this.mDownPointerInfo.currentY - this.mDownPointerInfo.downY)); + sb.append(')'); + sb.append(' '); + pad(sb, 4, (int) this.mDownPointerInfo.elapsedThreshold); + sb.append("ms"); + } + } + } + + private static void pad(StringBuilder sb, int len, int num) { + int n = num; + if (num < 0) { + n = Math.abs(num); + len--; + } + int nl = n > 0 ? ((int) Math.log10((double) n)) + 1 : 1; + while (true) { + int nl2 = nl + 1; + if (nl >= len) { + break; + } + sb.append(' '); + nl = nl2; + } + if (num < 0) { + sb.append('-'); + } + sb.append(n); + } + + private static List<float[]> allocatePoints() { + List<float[]> points = new ArrayList(); + for (int i = 0; i < MAX_POINTERS; i++) { + points.add(new float[MAX_POINTS]); + } + return points; + } + + private void onMotionEvent(MotionEvent ev) { + long evt; + int p; + Log.d(TAG, "EVENT " + ev); + if (ev.getActionMasked() == 0) { + clearScribbles(); + } + int hs = ev.getHistorySize(); + int ps = ev.getPointerCount(); + for (int h = 0; h < hs; h++) { + evt = ev.getHistoricalEventTime(h); + for (p = 0; p < ps; p++) { + int pid = ev.getPointerId(p); + float hx = ev.getHistoricalX(p, h); + float hy = ev.getHistoricalY(p, h); + String str = TAG; + Object[] objArr = new Object[MAX_POINTERS]; + objArr[0] = Long.valueOf(evt); + objArr[1] = Integer.valueOf(p); + objArr[2] = Integer.valueOf(pid); + objArr[3] = Float.valueOf(hx); + objArr[4] = Float.valueOf(hy); + Log.d(str, String.format("h.evt=%s p=%s pid=%s x=%s y=%s", objArr)); + recordScribblePoint(pid, hx, hy); + } + } + evt = ev.getEventTime(); + for (p = 0; p < ps; p++) { + int pid = ev.getPointerId(p); + float x = ev.getX(p); + float y = ev.getY(p); + String str = TAG; + Object[] objArr = new Object[MAX_POINTERS]; + objArr[0] = Long.valueOf(evt); + objArr[1] = Integer.valueOf(p); + objArr[2] = Integer.valueOf(pid); + objArr[3] = Float.valueOf(x); + objArr[4] = Float.valueOf(y); + Log.d(str, String.format("c.evt=%s p=%s pid=%s x=%s y=%s", objArr)); + recordScribblePoint(pid, x, y); + } + invalidate(); + } + + private void clearScribbles() { + for (int i = 0; i < this.mScribbleCounts.length; i++) { + this.mScribbleCounts[i] = 0; + } + } + + private void recordScribblePoint(int pid, float x, float y) { + if (pid < MAX_POINTERS) { + float[] pts = (float[]) this.mScribblePoints.get(pid); + int oldCount = this.mScribbleCounts[pid]; + if (oldCount + 4 >= MAX_POINTS) { + return; + } + int[] iArr; + if (oldCount == 0) { + pts[oldCount + 0] = x; + pts[oldCount + 1] = y; + iArr = this.mScribbleCounts; + iArr[pid] = iArr[pid] + 2; + return; + } + pts[oldCount + 0] = x; + pts[oldCount + 1] = y; + pts[oldCount + 2] = x; + pts[oldCount + 3] = y; + iArr = this.mScribbleCounts; + iArr[pid] = iArr[pid] + 4; + } + } +} diff --git a/KBars/app/src/main/java/js/kbars/TransparencyToggleButton.java b/KBars/app/src/main/java/js/kbars/TransparencyToggleButton.java new file mode 100644 index 0000000..ef14d85 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/TransparencyToggleButton.java @@ -0,0 +1,43 @@ +package js.kbars; + +import android.app.Activity; +import android.content.Context; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.Window; +import android.widget.Button; + +public final class TransparencyToggleButton extends Button { + private final String mDescription; + private boolean mTransparent; + private final int mWmFlag; + + public TransparencyToggleButton(Context context, String description, int wmFlag) { + super(context); + this.mDescription = description; + this.mWmFlag = wmFlag; + setOnClickListener(new OnClickListener() { + public void onClick(View v) { + TransparencyToggleButton.this.toggle("clicked"); + } + }); + update(); + } + + private void toggle(String reason) { + Log.d(KBarsActivity.TAG, "toggle reason=" + reason); + this.mTransparent = !this.mTransparent; + update(); + } + + private void update() { + setText("Make " + this.mDescription + " " + (this.mTransparent ? "opaque" : "transparent")); + Window w = ((Activity) getContext()).getWindow(); + if (this.mTransparent) { + w.addFlags(this.mWmFlag); + } else { + w.clearFlags(this.mWmFlag); + } + } +} diff --git a/KBars/app/src/main/java/js/kbars/Util.java b/KBars/app/src/main/java/js/kbars/Util.java new file mode 100644 index 0000000..5cd4971 --- /dev/null +++ b/KBars/app/src/main/java/js/kbars/Util.java @@ -0,0 +1,42 @@ +package js.kbars; + +import android.content.Context; +import android.content.pm.PackageManager.NameNotFoundException; +import android.util.DisplayMetrics; +import android.view.WindowManager; +import java.lang.reflect.Field; + +public class Util { + public static String logTag(Class<?> c) { + return "kbars." + c.getSimpleName(); + } + + public static Object getField(Object obj, String fieldName) { + Class<?> c = obj.getClass(); + try { + if (obj instanceof String) { + c = c.getClassLoader().loadClass((String) obj); + obj = null; + } + Field f = c.getDeclaredField(fieldName); + f.setAccessible(true); + return f.get(obj); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + public static int getDensityDpi(Context context) { + DisplayMetrics metrics = new DisplayMetrics(); + ((WindowManager) context.getSystemService("window")).getDefaultDisplay().getMetrics(metrics); + return metrics.densityDpi; + } + + public static String getVersionName(Context context) { + try { + return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; + } catch (NameNotFoundException e) { + throw new RuntimeException(e); + } + } +} diff --git a/KBars/app/src/main/res/drawable-hdpi-v4/ic_launcher.png b/KBars/app/src/main/res/drawable-hdpi-v4/ic_launcher.png Binary files differnew file mode 100644 index 0000000..b899b9e --- /dev/null +++ b/KBars/app/src/main/res/drawable-hdpi-v4/ic_launcher.png diff --git a/KBars/app/src/main/res/drawable-mdpi-v4/ic_launcher.png b/KBars/app/src/main/res/drawable-mdpi-v4/ic_launcher.png Binary files differnew file mode 100644 index 0000000..d2b481b --- /dev/null +++ b/KBars/app/src/main/res/drawable-mdpi-v4/ic_launcher.png diff --git a/KBars/app/src/main/res/drawable-xhdpi-v4/ic_launcher.png b/KBars/app/src/main/res/drawable-xhdpi-v4/ic_launcher.png Binary files differnew file mode 100644 index 0000000..4a26260 --- /dev/null +++ b/KBars/app/src/main/res/drawable-xhdpi-v4/ic_launcher.png diff --git a/KBars/app/src/main/res/drawable-xxhdpi-v4/ic_launcher.png b/KBars/app/src/main/res/drawable-xxhdpi-v4/ic_launcher.png Binary files differnew file mode 100644 index 0000000..cdae26b --- /dev/null +++ b/KBars/app/src/main/res/drawable-xxhdpi-v4/ic_launcher.png diff --git a/KBars/app/src/main/res/raw/clipcanvas.mp4 b/KBars/app/src/main/res/raw/clipcanvas.mp4 Binary files differnew file mode 100644 index 0000000..e41f4c7 --- /dev/null +++ b/KBars/app/src/main/res/raw/clipcanvas.mp4 diff --git a/KBars/app/src/main/res/values/strings.xml b/KBars/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..ea4b9c2 --- /dev/null +++ b/KBars/app/src/main/res/values/strings.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">(kbars)</string> + <string name="action_landscape">Landscape</string> + <string name="action_portrait">Portrait</string> + <string name="action_reverse_landscape">Reverse Landscape</string> + <string name="action_reverse_portrait">Reverse Portrait</string> +</resources> diff --git a/KBars/app/src/main/res/values/styles.xml b/KBars/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..fd4fc97 --- /dev/null +++ b/KBars/app/src/main/res/values/styles.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="AppBaseTheme"> + </style> + <style name="AppTheme"> + </style> +</resources> |