├── .gitignore ├── License ├── README.md ├── README_Dev.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ ├── android │ │ └── view │ │ │ └── ViewRootImpl.java │ └── com │ │ └── wanjian │ │ ├── dialog │ │ └── TransparentActivity.java │ │ └── sak │ │ └── demo │ │ ├── App.java │ │ ├── ContainerFragment.java │ │ ├── DialogAct.java │ │ ├── DialogTest.java │ │ ├── MainActivity.java │ │ ├── MyView.java │ │ ├── SecAct.java │ │ ├── SegmentFragment.java │ │ └── a │ │ └── fragment │ │ └── with │ │ └── a │ │ └── very │ │ └── very │ │ └── very │ │ └── longname │ │ └── that │ │ └── fragment │ │ └── name │ │ └── auto │ │ └── scale │ │ └── size │ │ └── ContentFragment.java │ └── res │ ├── drawable │ ├── border.xml │ └── color_selector.xml │ ├── layout │ ├── container_fragment.xml │ ├── dialog_act.xml │ ├── item.xml │ ├── layout.xml │ ├── popupwindow.xml │ ├── sec_act.xml │ ├── segment_fragment.xml │ ├── test.xml │ ├── user_toast.xml │ └── user_window.xml │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── sak_guide_activity_name.jpg ├── sak_guide_boder.jpg ├── sak_guide_drag.jpg ├── sak_guide_edit.jpg ├── sak_guide_edit_panel.jpg ├── sak_guide_fragment_name.jpg ├── sak_guide_func.jpg ├── sak_guide_grid.jpg ├── sak_guide_margin.jpg ├── sak_guide_measure.jpg ├── sak_guide_padding.jpg ├── sak_guide_performance.jpg ├── sak_guide_pickview.jpg ├── sak_guide_relative_distance.jpg ├── sak_guide_scalpel.jpg ├── sak_guide_take_color.jpg ├── sak_guide_text_color.jpg └── sak_guide_text_size.jpg ├── sak-nop ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── wanjian │ └── sak │ ├── SAK.java │ ├── config │ └── Config.java │ ├── converter │ ├── ISizeConverter.java │ └── Size.java │ ├── filter │ └── ViewFilter.java │ └── layer │ ├── AbsLayer.java │ └── adapter │ ├── LayerAdapter.java │ └── LayerTxtAdapter.java ├── saklib ├── .gitignore ├── build.gradle ├── compressed_pictures ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── wanjian │ │ └── sak │ │ ├── SAK.java │ │ ├── Scaffold.java │ │ ├── config │ │ ├── Config.java │ │ ├── Item.java │ │ └── Res.java │ │ ├── converter │ │ ├── ISizeConverter.java │ │ ├── OriginSizeConverter.java │ │ ├── Px2DpSizeConverter.java │ │ ├── Px2SpSizeConverter.java │ │ └── Size.java │ │ ├── event │ │ └── EventListener.java │ │ ├── filter │ │ └── ViewFilter.java │ │ ├── layer │ │ ├── AbsLayer.java │ │ ├── IClip.java │ │ ├── IRange.java │ │ ├── ISize.java │ │ ├── Layer.java │ │ ├── LayerRoot.java │ │ ├── adapter │ │ │ ├── LayerAdapter.java │ │ │ └── LayerTxtAdapter.java │ │ ├── impl │ │ │ ├── ActivityNameLayerView.java │ │ │ ├── BackgroundColorLayer.java │ │ │ ├── BitmapWidthHeightLayer.java │ │ │ ├── BorderLayer.java │ │ │ ├── FlashWindowLayer.java │ │ │ ├── FragmentNameLayer.java │ │ │ ├── GridLayer.java │ │ │ ├── HorizontalMeasureView.java │ │ │ ├── LayerTxtAdapter.java │ │ │ ├── MarginLayer.java │ │ │ ├── PaddingLayer.java │ │ │ ├── RelativeLayerView.java │ │ │ ├── ScalpelFrameLayout.java │ │ │ ├── TakeColorLayer.java │ │ │ ├── TextColorLayer.java │ │ │ ├── TextSizeLayer.java │ │ │ ├── TranslationLayerView.java │ │ │ ├── TreeView.java │ │ │ ├── VerticalMeasureView.java │ │ │ ├── ViewClassLayer.java │ │ │ ├── ViewLayer.java │ │ │ └── WidthHeightLayer.java │ │ └── impl_tmp │ │ │ ├── CornerMeasureView.java │ │ │ ├── InfoLayer.java │ │ │ ├── ViewEditView.java │ │ │ └── ViewPickerLayer.java │ │ ├── proxy │ │ └── ProxyArrayList.java │ │ ├── support │ │ ├── DragLayerView.java │ │ ├── FPSView.java │ │ └── ViewEditPanel.java │ │ ├── system │ │ ├── canvas │ │ │ └── compact │ │ │ │ ├── CanvasCompact.java │ │ │ │ ├── HardwareCanvasV21Impl.java │ │ │ │ ├── HardwareCanvasV23Impl.java │ │ │ │ ├── HardwareCanvasV24Impl.java │ │ │ │ ├── HardwareCanvasV26Impl.java │ │ │ │ ├── HardwareCanvasV29Impl.java │ │ │ │ ├── HardwareCanvasV31Impl.java │ │ │ │ └── SoftCanvas.java │ │ ├── canvaspool │ │ │ ├── CanvasPoolCompact.java │ │ │ ├── CanvasRecycleListener.java │ │ │ └── MySynchronizedPool.java │ │ ├── input │ │ │ ├── InputEventCompatProcessorV30.java │ │ │ ├── InputEventListener.java │ │ │ ├── InputEventProcessorCompact.java │ │ │ ├── InputEventReceiverCompact.java │ │ │ ├── InputEventReceiverHolder.java │ │ │ ├── InputEventReceiverV21Impl.java │ │ │ ├── InputEventReceiverV27Impl.java │ │ │ └── InputEventReceiverV29Impl.java │ │ ├── rendernode │ │ │ ├── RenderNodeCompact.java │ │ │ ├── RenderNodeV21Impl.java │ │ │ ├── RenderNodeV23Impl.java │ │ │ └── RenderNodeV29Impl.java │ │ ├── traversals │ │ │ ├── MyTraversalRunnable.java │ │ │ ├── ViewTraversalsCompact.java │ │ │ └── ViewTraversalsListener.java │ │ └── window │ │ │ └── compact │ │ │ ├── IWindowChangeListener.java │ │ │ ├── WindowRootViewCompactV16Impl.java │ │ │ ├── WindowRootViewCompactV18Impl.java │ │ │ ├── WindowRootViewCompactV19Impl.java │ │ │ └── WindowRootViewCompat.java │ │ ├── unsafe │ │ ├── ReflectUtils.java │ │ └── UnsafeProxy.java │ │ ├── utils │ │ ├── BitmapCreater.java │ │ ├── Check.java │ │ ├── LoopQueue.java │ │ ├── OptionPanelUtils.java │ │ ├── RunningActivityFetcher.java │ │ ├── ScreenUtils.java │ │ ├── SpanStrBuilder.java │ │ ├── Utils.java │ │ └── ViewInfo.java │ │ └── view │ │ ├── GridScroller.java │ │ ├── OptPanelView.java │ │ └── SAKContainerView.java │ └── res │ ├── animator │ └── sak_shake_animator.xml │ ├── drawable-xxhdpi │ ├── sak_background_color_icon.png │ ├── sak_border_icon.png │ ├── sak_checkbox_circle_checked.png │ ├── sak_checkbox_circle_unchecked.png │ ├── sak_color_picker_icon.png │ ├── sak_controller_type_icon.png │ ├── sak_corner_measure_icon.png │ ├── sak_custom_info_icon.png │ ├── sak_drag_icon.png │ ├── sak_edit_icon.png │ ├── sak_entrance_icon.png │ ├── sak_grid_icon.png │ ├── sak_hori_measure_icon.png │ ├── sak_icon_scale.png │ ├── sak_img_size.png │ ├── sak_launcher_icon.png │ ├── sak_layer_icon.png │ ├── sak_layout_tree_icon.png │ ├── sak_margin_icon.png │ ├── sak_padding_icon.png │ ├── sak_page_name_icon.png │ ├── sak_performance_icon.png │ ├── sak_pick_view.png │ ├── sak_relative_distance_icon.png │ ├── sak_shake_icon.png │ ├── sak_text_color_icon.png │ ├── sak_text_size_icon.png │ ├── sak_ver_measure_icon.png │ └── sak_width_height_icon.png │ ├── drawable │ ├── sak_box_bag.xml │ ├── sak_card_background.xml │ ├── sak_circle_check_box_bag.xml │ ├── sak_corner_but_bag.xml │ ├── sak_divider.xml │ ├── sak_edittext_focused.xml │ ├── sak_edittext_normal.xml │ ├── sak_function_item_bag.xml │ ├── sak_icon_arrow_down.png │ ├── sak_input_bg.xml │ ├── sak_radiogroup_divider.xml │ └── sak_toast_bag.xml │ ├── layout │ ├── sak_edit_panel_layout.xml │ ├── sak_function_item.xml │ ├── sak_opt_panel_view.xml │ ├── sak_performance_layout.xml │ ├── sak_radiobutton.xml │ ├── sak_scalpel_opt_view.xml │ ├── sak_toast_layout.xml │ └── sak_view_info_layout.xml │ ├── values-zh │ └── strings.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── settings.gradle └── systemlib ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml └── java └── android ├── graphics ├── FrameInfo.java ├── HardwareRenderer.java ├── RecordingCanvas.java └── RenderNode.java ├── util └── Pools.java └── view ├── DisplayListCanvas.java ├── GLES20RecordingCanvas.java ├── HardwareCanvas.java ├── HardwareLayer.java ├── HardwareRenderer.java ├── InputChannel.java ├── InputEventCompatProcessor.java ├── InputEventReceiver.java ├── RenderNode.java ├── ThreadedRenderer.java ├── ViewFrameInfo.java └── ViewRootImpl.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/ 38 | 39 | # Keystore files 40 | *.jks 41 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 https://github.com/android-notes/SwissArmyKnife wanjian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwissArmyKnife 2 | 3 | 4 | ### SwissArmyKnife 5 | 6 | 兼容Android5~16 7 | 8 | SwissArmyKnife 是一款方便调试android UI的工具。可以直接在android设备屏幕上显示控件的相关信息。3.x版本对根View没有任何要求,可以是任意类型的view。 9 | 3.x需要弹窗权限。由于时间有限,暂未兼容Android5.0以下设备 10 | 11 | 12 | ### 接入方式 13 | 14 | ``` 15 | allprojects { 16 | repositories { 17 | ... 18 | maven { url 'https://jitpack.io' } 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation 'com.github.android-notes.SwissArmyKnife:saklib:4.0.6' 24 | } 25 | ``` 26 | 27 | ``` 28 | 开启 29 | SAK.init(Application application, Config config) 30 | 31 | ``` 32 | 33 | 备注:需要使用 implementation 'org.lsposed.hiddenapibypass:hiddenapibypass:6.1' 34 | 35 | ### 功能界面 36 | 37 | ![image](https://raw.githubusercontent.com/android-notes/SwissArmyKnife/master/img/sak_guide_func.jpg) 38 | 39 | 40 | ### 拾取控件 41 | 42 | 开启拾取控件选项后,拖动圆环到要拾取的控件位置即可。可以获取字体颜色,大小,背景色等信息(支持SpannableString) 43 | 44 | ![image](https://raw.githubusercontent.com/android-notes/SwissArmyKnife/master/img/sak_guide_pickview.jpg) 45 | 46 | 47 | 48 | 49 | ### 相对距离 50 | 51 | 开启相对距离选项后,依次`长按`两个控件即可显示两个控件间的水平和竖直距离,距离默认单位是dp,可以通过功能界面的单位选项切换单位`(该功能和编辑控件、移动控件功能冲突,请勿同时开启)` 52 | 53 | ![image](https://raw.githubusercontent.com/android-notes/SwissArmyKnife/master/img/sak_guide_relative_distance.jpg) 54 | 55 | 56 | 57 | ### 移动控件 58 | 59 | 开启移动控件选项后,`长按`控件即可拖动,距离默认单位是dp,可以通过功能界面的单位选项切换单位`(该功能和编辑控件、移动控件功能冲突,请勿同时开启)` 60 | 61 | ![image](https://raw.githubusercontent.com/android-notes/SwissArmyKnife/master/img/sak_guide_drag.jpg) 62 | 63 | 64 | ### 取色器 65 | 66 | 开启取色器选项后,会在屏幕显示 绿色圆环,可以任意拖动,屏幕下方会显示圆环中心的颜色值 67 | 68 | ![image](https://raw.githubusercontent.com/android-notes/SwissArmyKnife/master/img/sak_guide_take_color.jpg) 69 | 70 | 71 | ### 水平直尺,竖直直尺 72 | 73 | 开启后会在屏幕显示水平直尺和竖直直尺,可以任意拖动。直尺上有两个值,一个单位是px,另一个是dp 74 | 75 | ![image](https://raw.githubusercontent.com/android-notes/SwissArmyKnife/master/img/sak_guide_measure.jpg) 76 | 77 | 78 | 79 | ### 外边距/内边距 80 | 81 | 开启后可以看到任意一个view的外边距,边距单位默认为dp,可以通过功能界面的单位选项切换单位。`可以通过功能界面的层级区间过滤掉部分view,避免数值相互覆盖` 82 | 83 | ![image](https://raw.githubusercontent.com/android-notes/SwissArmyKnife/master/img/sak_guide_margin.jpg) 84 | 85 | > 宽高、字体大小、字体颜色、背景色等使用方式同 外边距/内边距,也可以通过 单位选项和层级区间进行控制 86 | 87 | 88 | 89 | ### Fragment名称、Activity名称 90 | 91 | 开启后可以看到当前Activity的类名,每一个Fragment的类名。可以通过功能界面的层级区间过滤掉部分Fragment,避免Fragment名称相互覆盖 92 | 93 | ![image](https://raw.githubusercontent.com/android-notes/SwissArmyKnife/master/img/sak_guide_fragment_name.jpg) 94 | 95 | 96 | ## 裁剪绘制范围 97 | 98 | 若内外边距、宽高、字体颜色等信息`不显示,可以关闭 裁剪绘制`。开启该功能可以避免 可以滚动的控件滚动后导致的信息覆盖。 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /README_Dev.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 33 5 | namespace('com.wanjian.sak.demo') 6 | defaultConfig { 7 | minSdkVersion 15 8 | targetSdkVersion 33 9 | versionCode 1 10 | versionName "1.0" 11 | applicationId 'com.wanjian.sak.demo' 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | 20 | lintOptions { 21 | abortOnError false 22 | } 23 | 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(include: ['*.jar'], dir: 'libs') 28 | implementation 'org.lsposed.hiddenapibypass:hiddenapibypass:6.1' 29 | implementation('androidx.fragment:fragment:1.0.0') 30 | implementation project(':saklib') 31 | 32 | 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/wanjian/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/wanjian/dialog/TransparentActivity.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.dialog; 2 | 3 | import android.app.Activity; 4 | 5 | public class TransparentActivity extends Activity { 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/wanjian/sak/demo/App.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.demo; 2 | 3 | import android.app.Application; 4 | import android.os.Build; 5 | 6 | import org.lsposed.hiddenapibypass.HiddenApiBypass; 7 | 8 | 9 | /** 10 | * Created by wanjian on 2018/2/9. 11 | */ 12 | 13 | public class App extends Application { 14 | @Override 15 | public void onCreate() { 16 | super.onCreate(); 17 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 18 | HiddenApiBypass.addHiddenApiExemptions(""); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/wanjian/sak/demo/ContainerFragment.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.demo; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import androidx.annotation.Nullable; 9 | import androidx.fragment.app.Fragment; 10 | 11 | public class ContainerFragment extends Fragment { 12 | @Nullable 13 | @Override 14 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 15 | return inflater.inflate(R.layout.container_fragment, container, false); 16 | } 17 | 18 | @Override 19 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 20 | super.onViewCreated(view, savedInstanceState); 21 | getChildFragmentManager().beginTransaction().replace(R.id.leftContainer, new SegmentFragment()).commit(); 22 | getChildFragmentManager().beginTransaction().replace(R.id.rightContainer, new SegmentFragment()).commit(); 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/wanjian/sak/demo/DialogAct.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.demo; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.fragment.app.Fragment; 6 | import androidx.fragment.app.FragmentActivity; 7 | 8 | /** 9 | * Created by wanjian on 2017/4/1. 10 | */ 11 | 12 | public class DialogAct extends FragmentActivity { 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | 18 | 19 | setContentView(R.layout.dialog_act); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/wanjian/sak/demo/DialogTest.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.demo; 2 | 3 | class DialogTest { 4 | } 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/wanjian/sak/demo/MyView.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.demo; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.os.Handler; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | /** 12 | * Created by wanjian on 2017/4/1. 13 | */ 14 | 15 | public class MyView extends View { 16 | Handler mHandler = new Handler(); 17 | int v = 0; 18 | Runnable runnable = new Runnable() { 19 | @Override 20 | public void run() { 21 | v++; 22 | invalidate(); 23 | mHandler.postDelayed(this, 1000); 24 | } 25 | }; 26 | Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 27 | public MyView(Context context) { 28 | super(context); 29 | init(); 30 | } 31 | 32 | public MyView(Context context, AttributeSet attrs) { 33 | super(context, attrs); 34 | init(); 35 | } 36 | 37 | private void init() { 38 | mPaint.setTextSize(50); 39 | mPaint.setColor(Color.RED); 40 | mHandler.postDelayed(runnable, 1000); 41 | } 42 | 43 | @Override 44 | protected void onDraw(Canvas canvas) { 45 | super.onDraw(canvas); 46 | canvas.drawText("" + v, 10, getHeight() / 2, mPaint); 47 | } 48 | 49 | @Override 50 | protected void onDetachedFromWindow() { 51 | super.onDetachedFromWindow(); 52 | mHandler.removeCallbacks(runnable); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/wanjian/sak/demo/SegmentFragment.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.demo; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import androidx.annotation.Nullable; 9 | import androidx.fragment.app.Fragment; 10 | 11 | import com.wanjian.sak.demo.a.fragment.with.a.very.very.very.longname.that.fragment.name.auto.scale.size.ContentFragment; 12 | 13 | 14 | public class SegmentFragment extends Fragment { 15 | @Nullable 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 18 | return inflater.inflate(R.layout.segment_fragment, container, false); 19 | } 20 | 21 | @Override 22 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 23 | super.onViewCreated(view, savedInstanceState); 24 | view.setBackgroundColor(((int) (Math.random() * Integer.MAX_VALUE)) | 0xFF000000); 25 | getChildFragmentManager().beginTransaction().replace(R.id.container, new ContentFragment()).commit(); 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/wanjian/sak/demo/a/fragment/with/a/very/very/very/longname/that/fragment/name/auto/scale/size/ContentFragment.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.demo.a.fragment.with.a.very.very.very.longname.that.fragment.name.auto.scale.size; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.Nullable; 10 | import androidx.fragment.app.Fragment; 11 | 12 | public class ContentFragment extends Fragment { 13 | @Nullable 14 | @Override 15 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 16 | TextView textView = new TextView(container.getContext()); 17 | int color = ((int) (Math.random() * Integer.MAX_VALUE)) | 0xFF000000; 18 | textView.setBackgroundColor(color); 19 | textView.setText(Integer.toHexString(color)); 20 | return textView; 21 | } 22 | 23 | @Override 24 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 25 | super.onViewCreated(view, savedInstanceState); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/border.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/container_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | 20 | 21 | 26 | 27 | 28 | 29 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_act.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 18 | 19 | 23 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/popupwindow.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/segment_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/test.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/user_toast.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 18 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/user_window.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 19 | 20 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 70dp 4 | 90dp 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SAK Autopilot 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | google() 7 | } 8 | dependencies { 9 | classpath "com.android.tools.build:gradle:7.4.2" 10 | // classpath 'com.novoda:bintray-release:0.8.0' 11 | // classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' 12 | 13 | // classpath "com.wanjian.plugin:tinypng:0.0.6" 14 | // classpath 'com.android.tools.build:gradle:1.2.3' 15 | // classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2' 16 | // classpath 'com.github.dcendents:android-maven-plugin:1.2' 17 | // NOTE: Do not place your application dependencies here; they belong 18 | // in the individual module build.gradle files 19 | } 20 | } 21 | 22 | task clean(type: Delete) { 23 | delete rootProject.buildDir 24 | } 25 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | android.useAndroidX=true 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Feb 05 13:11:24 CST 2025 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /img/sak_guide_activity_name.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_activity_name.jpg -------------------------------------------------------------------------------- /img/sak_guide_boder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_boder.jpg -------------------------------------------------------------------------------- /img/sak_guide_drag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_drag.jpg -------------------------------------------------------------------------------- /img/sak_guide_edit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_edit.jpg -------------------------------------------------------------------------------- /img/sak_guide_edit_panel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_edit_panel.jpg -------------------------------------------------------------------------------- /img/sak_guide_fragment_name.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_fragment_name.jpg -------------------------------------------------------------------------------- /img/sak_guide_func.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_func.jpg -------------------------------------------------------------------------------- /img/sak_guide_grid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_grid.jpg -------------------------------------------------------------------------------- /img/sak_guide_margin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_margin.jpg -------------------------------------------------------------------------------- /img/sak_guide_measure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_measure.jpg -------------------------------------------------------------------------------- /img/sak_guide_padding.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_padding.jpg -------------------------------------------------------------------------------- /img/sak_guide_performance.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_performance.jpg -------------------------------------------------------------------------------- /img/sak_guide_pickview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_pickview.jpg -------------------------------------------------------------------------------- /img/sak_guide_relative_distance.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_relative_distance.jpg -------------------------------------------------------------------------------- /img/sak_guide_scalpel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_scalpel.jpg -------------------------------------------------------------------------------- /img/sak_guide_take_color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_take_color.jpg -------------------------------------------------------------------------------- /img/sak_guide_text_color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_text_color.jpg -------------------------------------------------------------------------------- /img/sak_guide_text_size.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/img/sak_guide_text_size.jpg -------------------------------------------------------------------------------- /sak-nop/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sak-nop/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | android { 3 | namespace('com.wanjian.sak') 4 | compileSdkVersion 33 5 | defaultConfig { 6 | minSdkVersion 14 7 | targetSdkVersion 33 8 | versionCode 1 9 | versionName "1.0" 10 | } 11 | buildTypes { 12 | release { 13 | minifyEnabled false 14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 15 | } 16 | } 17 | 18 | lintOptions { 19 | abortOnError false 20 | } 21 | 22 | } 23 | 24 | 25 | dependencies { 26 | } 27 | -------------------------------------------------------------------------------- /sak-nop/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /sak-nop/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /sak-nop/src/main/java/com/wanjian/sak/SAK.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak; 2 | 3 | import android.app.Application; 4 | 5 | import com.wanjian.sak.config.Config; 6 | 7 | /** 8 | * Created by wanjian on 2017/2/20. 9 | */ 10 | 11 | public class SAK { 12 | 13 | public static void init(Application application, Config config) { 14 | 15 | } 16 | 17 | private SAK() { 18 | } 19 | 20 | public static void unInstall() { 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /sak-nop/src/main/java/com/wanjian/sak/config/Config.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.config; 2 | 3 | import android.content.Context; 4 | 5 | import com.wanjian.sak.converter.ISizeConverter; 6 | import com.wanjian.sak.filter.ViewFilter; 7 | import com.wanjian.sak.layer.AbsLayer; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Created by wanjian on 2017/2/20. 13 | */ 14 | 15 | public class Config { 16 | 17 | 18 | public List getLayerViews() { 19 | return null; 20 | } 21 | 22 | public List getSizeConverters() { 23 | 24 | return null; 25 | } 26 | 27 | public int getStartRange() { 28 | return 0; 29 | } 30 | 31 | public void setStartRange(int startRange) { 32 | } 33 | 34 | public int getEndRange() { 35 | return 0; 36 | } 37 | 38 | public void setEndRange(int endRange) { 39 | } 40 | 41 | public boolean isClipDraw() { 42 | return false; 43 | } 44 | 45 | public void setClipDraw(boolean clipDraw) { 46 | } 47 | 48 | public int getMinRange() { 49 | return 0; 50 | } 51 | 52 | public int getMaxRange() { 53 | return 0; 54 | } 55 | 56 | public static class Build { 57 | 58 | public Build(Context context) { 59 | } 60 | 61 | public Build addSizeConverter(ISizeConverter sizeConverter) { 62 | return this; 63 | } 64 | 65 | public Build addLayerView(AbsLayer layerView) { 66 | return this; 67 | } 68 | 69 | public Build viewFilter(ViewFilter viewFilter) { 70 | return this; 71 | } 72 | 73 | public Build range(int min, int max) { 74 | 75 | return this; 76 | } 77 | 78 | public Build clipDraw(boolean clip) { 79 | 80 | return this; 81 | } 82 | 83 | public Config build() { 84 | return null; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /sak-nop/src/main/java/com/wanjian/sak/converter/ISizeConverter.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.converter; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by wanjian on 2017/2/20. 7 | */ 8 | 9 | public abstract class ISizeConverter { 10 | public static ISizeConverter CONVERTER; 11 | 12 | public abstract String desc(); 13 | 14 | public abstract Size convert(Context context, float length); 15 | 16 | public abstract int recovery(Context context, float length); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /sak-nop/src/main/java/com/wanjian/sak/converter/Size.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.converter; 2 | 3 | 4 | /** 5 | * Created by wanjian on 2017/2/20. 6 | */ 7 | 8 | public class Size { 9 | 10 | private Size() { 11 | } 12 | 13 | public Size(int length, String unit) { 14 | 15 | } 16 | 17 | public static Size obtain() { 18 | 19 | return null; 20 | } 21 | 22 | public float getLength() { 23 | return 0; 24 | } 25 | 26 | public Size setLength(float length) { 27 | return this; 28 | } 29 | 30 | public String getUnit() { 31 | return null; 32 | } 33 | 34 | public Size setUnit(String unit) { 35 | return this; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /sak-nop/src/main/java/com/wanjian/sak/filter/ViewFilter.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.filter; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * Created by wanjian on 2017/2/20. 7 | */ 8 | 9 | public abstract class ViewFilter { 10 | public static ViewFilter FILTER; 11 | 12 | public final boolean filter(View view) { 13 | return false; 14 | } 15 | 16 | protected abstract boolean apply(View view); 17 | } 18 | -------------------------------------------------------------------------------- /sak-nop/src/main/java/com/wanjian/sak/layer/AbsLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.drawable.Drawable; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.view.WindowManager; 9 | import android.widget.FrameLayout; 10 | 11 | import com.wanjian.sak.config.Config; 12 | import com.wanjian.sak.converter.ISizeConverter; 13 | import com.wanjian.sak.filter.ViewFilter; 14 | 15 | /** 16 | * Created by wanjian on 2017/3/9. 17 | */ 18 | 19 | public abstract class AbsLayer extends FrameLayout { 20 | 21 | public AbsLayer(Context context) { 22 | super(context); 23 | } 24 | 25 | public void attachConfig(Config config) { 26 | } 27 | 28 | public abstract String description(); 29 | 30 | public abstract Drawable icon(); 31 | 32 | public final void enable(boolean enable) { 33 | } 34 | 35 | protected void onStateChange(boolean isEnable) { 36 | 37 | } 38 | 39 | public final boolean isEnable() { 40 | return false; 41 | } 42 | 43 | protected boolean isClipDraw() { 44 | return false; 45 | } 46 | 47 | protected int getStartRange() { 48 | return 0; 49 | } 50 | 51 | protected int getEndRange() { 52 | return 0; 53 | } 54 | 55 | public final void uiUpdate(Canvas canvas, View view) { 56 | 57 | } 58 | 59 | protected void onUiUpdate(Canvas canvas, View rootView) { 60 | 61 | } 62 | 63 | protected void onAttached(View rootView) { 64 | } 65 | 66 | 67 | protected void onDetached(View rootView) { 68 | } 69 | 70 | protected int[] getLocationAndSize(View view) { 71 | return null; 72 | } 73 | 74 | protected int dp2px(int dip) { 75 | return 0; 76 | } 77 | 78 | protected int px2dp(float pxValue) { 79 | return 0; 80 | } 81 | 82 | protected ISizeConverter getSizeConverter() { 83 | return null; 84 | } 85 | 86 | protected ViewFilter getViewFilter() { 87 | return null; 88 | } 89 | 90 | protected void showWindow(View view, WindowManager.LayoutParams params) { 91 | 92 | } 93 | 94 | protected void updateWindow(View view, WindowManager.LayoutParams params) { 95 | } 96 | 97 | protected void removeWindow(View view) { 98 | } 99 | 100 | public ViewGroup.LayoutParams getLayoutParams(FrameLayout.LayoutParams params) { 101 | return null; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /sak-nop/src/main/java/com/wanjian/sak/layer/adapter/LayerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.adapter; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.view.View; 6 | 7 | import com.wanjian.sak.layer.AbsLayer; 8 | 9 | 10 | /** 11 | * Created by wanjian on 2016/10/23. 12 | */ 13 | 14 | public abstract class LayerAdapter extends AbsLayer { 15 | 16 | public LayerAdapter(Context context) { 17 | super(context); 18 | } 19 | 20 | @Override 21 | protected void onUiUpdate(Canvas canvas, View rootView) { 22 | } 23 | 24 | 25 | protected abstract void onDrawLayer(Canvas canvas, View view); 26 | } 27 | -------------------------------------------------------------------------------- /sak-nop/src/main/java/com/wanjian/sak/layer/adapter/LayerTxtAdapter.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.adapter; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.view.View; 6 | 7 | /** 8 | * Created by wanjian on 2016/10/26. 9 | *

10 | * 在view左上角画浅白色背景和文本 11 | */ 12 | 13 | public abstract class LayerTxtAdapter extends LayerAdapter { 14 | 15 | public LayerTxtAdapter(Context context) { 16 | super(context); 17 | } 18 | 19 | 20 | @Override 21 | protected void onDrawLayer(Canvas canvas, View view) { 22 | 23 | } 24 | 25 | protected abstract String getTxt(View view); 26 | 27 | 28 | protected int getColor() { 29 | return 0; 30 | } 31 | 32 | protected int getBackgroundColor() { 33 | return 0; 34 | } 35 | 36 | public float getTextSize() { 37 | return 0; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /saklib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /saklib/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'maven-publish' 3 | android { 4 | namespace('com.wanjian.sak') 5 | compileSdkVersion 33 6 | defaultConfig { 7 | minSdkVersion 14 8 | targetSdkVersion 33 9 | versionCode 1 10 | versionName "1.0" 11 | } 12 | buildTypes { 13 | release { 14 | minifyEnabled false 15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 16 | } 17 | } 18 | 19 | lintOptions { 20 | abortOnError false 21 | } 22 | 23 | } 24 | 25 | dependencies { 26 | implementation fileTree(dir: 'libs', include: ['*.jar']) 27 | implementation('androidx.fragment:fragment:1.0.0') 28 | compileOnly project(path: ':systemlib') 29 | } 30 | 31 | publishing { 32 | publications { 33 | release(MavenPublication) { 34 | groupId = 'com.github.android-notes' 35 | artifactId = 'SwissArmyKnife' 36 | version = '4.0.6' 37 | 38 | afterEvaluate { 39 | from components.release 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /saklib/compressed_pictures: -------------------------------------------------------------------------------- 1 | # Do not modify this file ! 2 | 1d945fdbaabefd7e3986dbe077868342 3 | 240eea45ebcb7c237bc3a346641ac7d7 4 | 27a7284489529b58f6b374d8116b0d29 5 | 280d8b92c8da65e545e31d12be9acee0 6 | 34dc3eba1f9167f6fa2667524ea375ad 7 | 3637923ded651ab8920168363d7ddc20 8 | 3692b48641664eb215cdc11caa40b94e 9 | 56ddc2b73473e056f7b61c216ea6cc6a 10 | 58306a5cf9b21e211d6f60c0f30f64df 11 | 5a0d35c1128a25d8418b3f5537f3dd91 12 | 69faa2c2dad502cb6bbaf63d10fe5c24 13 | 7a507bd56fc6a22c7c5268ed7d3deb74 14 | 7b527e6dc1ada3147423c11b5a4a045d 15 | 8440cfd5441ed66343579b0642bb4370 16 | 85b1e055efc190e649c23498ff224aa8 17 | 894a888fd0631ba8d4d4753fdafb4bee 18 | 9b550082c308a17e91b6976b7daba208 19 | 9f8775e185d0253ffcf512795f23dd12 20 | b93043c06e5790e316979cdb2a57fdea 21 | c29b1c79f3fa2ec21df1c31e431e7da0 22 | e989ecb07a56e9ae51ef982609315533 23 | ed6a27fab5ab85611bfb453d7f52c1c6 24 | edb7c8ded87e279e546303644cce5b45 25 | edcb4e91f3a8b41cd59aa758c381d6f2 26 | feb4a4069c8d94d966cc782d24f14c67 -------------------------------------------------------------------------------- /saklib/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/wanjian/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /saklib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/Scaffold.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak; 2 | 3 | import android.app.Application; 4 | import android.os.Build; 5 | import android.view.InputEvent; 6 | import android.view.View; 7 | import android.view.ViewRootImpl; 8 | 9 | import com.wanjian.sak.config.Config; 10 | import com.wanjian.sak.layer.LayerRoot; 11 | import com.wanjian.sak.system.input.InputEventListener; 12 | import com.wanjian.sak.system.input.InputEventProcessorCompact; 13 | import com.wanjian.sak.system.input.InputEventReceiverCompact; 14 | import com.wanjian.sak.system.traversals.ViewTraversalsCompact; 15 | import com.wanjian.sak.system.traversals.ViewTraversalsListener; 16 | import com.wanjian.sak.system.window.compact.IWindowChangeListener; 17 | import com.wanjian.sak.system.window.compact.WindowRootViewCompat; 18 | import com.wanjian.sak.utils.OptionPanelUtils; 19 | import com.wanjian.sak.view.SAKContainerView; 20 | 21 | //import com.wanjian.sak.system.canvas.compact.CanvasHolder; 22 | 23 | final class Scaffold { 24 | private static Application sApplication; 25 | 26 | public void install(final Application application, final Config config) { 27 | sApplication = application; 28 | WindowRootViewCompat.get(application).addWindowChangeListener(new IWindowChangeListener() { 29 | 30 | @Override 31 | public void onAddWindow(final ViewRootImpl viewRootImpl, final View view) { 32 | if (view instanceof SAKContainerView) { 33 | return; 34 | } 35 | view.post(new Runnable() { 36 | @Override 37 | public void run() { 38 | LayerRoot layerRoot = LayerRoot.create(config, viewRootImpl, view, sApplication); 39 | OptionPanelUtils.enableIfNeeded(layerRoot); 40 | observerUIChange(config, layerRoot, viewRootImpl, view); 41 | observerInputEvent(config, layerRoot, viewRootImpl, view); 42 | OptionPanelUtils.addLayerRoot(layerRoot); 43 | } 44 | }); 45 | } 46 | 47 | @Override 48 | public void onRemoveWindow(ViewRootImpl viewRootImpl, View view) { 49 | // CanvasHolder.release(viewRootImpl); 50 | } 51 | }); 52 | OptionPanelUtils.showEntrance(application, config); 53 | } 54 | 55 | 56 | private void observerInputEvent(Config config, final LayerRoot layerRoot, final ViewRootImpl viewRootImpl, final View rootView) { 57 | InputEventListener listener = new InputEventListener() { 58 | @Override 59 | public boolean onBeforeInputEvent(InputEvent inputEvent) { 60 | return layerRoot.beforeInputEvent(rootView, inputEvent); 61 | } 62 | 63 | @Override 64 | public void onAfterInputEvent(InputEvent inputEvent) { 65 | layerRoot.afterInputEvent(rootView, inputEvent); 66 | } 67 | }; 68 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 69 | InputEventProcessorCompact.get(rootView.getContext(),viewRootImpl, listener); 70 | } else { 71 | InputEventReceiverCompact.get(viewRootImpl, listener); 72 | } 73 | } 74 | 75 | private void observerUIChange(Config config, final LayerRoot layerRoot, ViewRootImpl viewRootImpl, View view) { 76 | new ViewTraversalsCompact().register(viewRootImpl, view, new ViewTraversalsListener() { 77 | @Override 78 | public void onBeforeTraversal(View rootView) { 79 | layerRoot.beforeTraversal(rootView); 80 | } 81 | 82 | @Override 83 | public void onAfterTraversal(View rootView) { 84 | layerRoot.afterTraversal(rootView); 85 | } 86 | }); 87 | } 88 | 89 | 90 | // public void unInstall() { 91 | // 92 | // } 93 | } 94 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/config/Item.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.config; 2 | 3 | import android.graphics.drawable.Drawable; 4 | 5 | import com.wanjian.sak.layer.Layer; 6 | 7 | public class Item { 8 | public Class layerType; 9 | public Drawable icon; 10 | public String name; 11 | private boolean isEnable; 12 | public Item(Class layerType, Drawable icon, String name) { 13 | this.layerType = layerType; 14 | this.icon = icon; 15 | this.name = name; 16 | } 17 | 18 | public boolean isEnable() { 19 | return isEnable; 20 | } 21 | 22 | public void setEnable(boolean enable) { 23 | isEnable = enable; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/converter/ISizeConverter.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.converter; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by wanjian on 2017/2/20. 7 | */ 8 | 9 | public abstract class ISizeConverter { 10 | public static ISizeConverter CONVERTER = new Px2DpSizeConverter(); 11 | 12 | public abstract String desc(); 13 | 14 | public abstract Size convert(Context context, float length); 15 | 16 | public abstract int recovery(Context context, float length); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/converter/OriginSizeConverter.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.converter; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by wanjian on 2017/2/20. 7 | */ 8 | 9 | public class OriginSizeConverter extends ISizeConverter { 10 | 11 | 12 | @Override 13 | public String desc() { 14 | return "Px"; 15 | } 16 | 17 | @Override 18 | public Size convert(Context context, float length) { 19 | Size size = Size.obtain(); 20 | 21 | size.setLength(length); 22 | size.setUnit("px"); 23 | 24 | return size; 25 | } 26 | 27 | @Override 28 | public int recovery(Context context, float length) { 29 | return (int) length; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/converter/Px2DpSizeConverter.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.converter; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by wanjian on 2017/2/20. 7 | */ 8 | 9 | public class Px2DpSizeConverter extends ISizeConverter { 10 | @Override 11 | public String desc() { 12 | return "Dp"; 13 | } 14 | 15 | @Override 16 | public Size convert(Context context, float length) { 17 | Size size = Size.obtain(); 18 | 19 | size.setLength(px2dp(context, length)); 20 | 21 | size.setUnit("dp"); 22 | 23 | return size; 24 | } 25 | 26 | @Override 27 | public int recovery(Context context, float length) { 28 | float scale = context.getResources().getDisplayMetrics().density; 29 | return (int) (length * scale + 0.5f); 30 | } 31 | 32 | private int px2dp(Context context, float px) { 33 | final float scale = context.getResources().getDisplayMetrics().density; 34 | return (int) (px / scale + 0.5f); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/converter/Px2SpSizeConverter.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.converter; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by wanjian on 2017/3/9. 7 | */ 8 | 9 | public class Px2SpSizeConverter extends ISizeConverter { 10 | @Override 11 | public String desc() { 12 | return "Sp"; 13 | } 14 | 15 | @Override 16 | public Size convert(Context context, float length) { 17 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 18 | return Size.obtain().setLength((int) (length / fontScale + 0.5f)).setUnit("sp"); 19 | } 20 | 21 | @Override 22 | public int recovery(Context context, float length) { 23 | float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 24 | return (int) (length * fontScale + 0.5f); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/converter/Size.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.converter; 2 | 3 | 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by wanjian on 2017/2/20. 9 | */ 10 | 11 | public class Size { 12 | 13 | private static List sList = new LinkedList<>(); 14 | private float length; 15 | private String unit; 16 | 17 | private Size() { 18 | } 19 | 20 | public Size(int length, String unit) { 21 | this.length = length; 22 | this.unit = unit; 23 | } 24 | 25 | public static Size obtain() { 26 | // if (sList.isEmpty()) { 27 | // return new Size(); 28 | // } 29 | // 30 | // return sList.get(0); 31 | 32 | return new Size(); 33 | } 34 | 35 | public float getLength() { 36 | return length; 37 | } 38 | 39 | public Size setLength(float length) { 40 | this.length = length; 41 | return this; 42 | } 43 | 44 | public String getUnit() { 45 | return unit; 46 | } 47 | 48 | public Size setUnit(String unit) { 49 | this.unit = unit; 50 | return this; 51 | } 52 | 53 | // public static void returnSize(Size size) { 54 | // Check.isNull(size, "size"); 55 | // if (sList.size() < 100) { 56 | // sList.add(size); 57 | // } 58 | // } 59 | 60 | @Override 61 | public String toString() { 62 | return length + " " + unit; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/event/EventListener.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.event; 2 | 3 | import android.view.InputEvent; 4 | import android.view.View; 5 | 6 | public interface EventListener { 7 | 8 | void beforeTraversal(View rootView); 9 | 10 | void afterTraversal(View rootView); 11 | 12 | boolean beforeInputEvent(View rootView, InputEvent event); 13 | 14 | void afterInputEvent(View rootView, InputEvent event); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/filter/ViewFilter.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.filter; 2 | 3 | import android.view.View; 4 | 5 | 6 | /** 7 | * Created by wanjian on 2017/2/20. 8 | */ 9 | 10 | public abstract class ViewFilter { 11 | public static ViewFilter FILTER = new ViewFilter() { 12 | @Override 13 | protected boolean apply(View view) { 14 | return view.getVisibility() == View.VISIBLE; 15 | } 16 | }; 17 | 18 | 19 | public final boolean filter(View view) { 20 | return apply(view); 21 | } 22 | 23 | protected abstract boolean apply(View view); 24 | 25 | @Override 26 | public int hashCode() { 27 | return getClass().hashCode(); 28 | } 29 | 30 | @Override 31 | public boolean equals(Object obj) { 32 | if (obj == null) { 33 | return false; 34 | } 35 | return obj.getClass() == getClass(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/IClip.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer; 2 | 3 | public interface IClip { 4 | void onClipChange(boolean clip); 5 | } 6 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/IRange.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer; 2 | 3 | public interface IRange { 4 | void onStartRangeChange(int start); 5 | void onEndRangeChange(int start); 6 | } 7 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/ISize.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer; 2 | 3 | import com.wanjian.sak.converter.ISizeConverter; 4 | 5 | public interface ISize { 6 | void onSizeConvertChange(ISizeConverter converter); 7 | } 8 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/Layer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer; 2 | 3 | import android.app.Application; 4 | import android.graphics.Canvas; 5 | import android.view.InputEvent; 6 | import android.view.View; 7 | import android.view.ViewRootImpl; 8 | 9 | import com.wanjian.sak.config.Config; 10 | import com.wanjian.sak.event.EventListener; 11 | import com.wanjian.sak.system.rendernode.RenderNodeCompact; 12 | 13 | public abstract class Layer implements EventListener { 14 | private ViewRootImpl viewRootImpl; 15 | private Config config; 16 | private Application application; 17 | private LayerRoot layerRoot; 18 | private RenderNodeCompact renderNode; 19 | private View rootView; 20 | private boolean isEnable; 21 | 22 | public Layer() { 23 | 24 | } 25 | 26 | public RenderNodeCompact getRenderNode() { 27 | return renderNode; 28 | } 29 | 30 | public final void attach(Config config, ViewRootImpl viewRoot, View rootView, Application application, LayerRoot layerRoot) { 31 | this.viewRootImpl = viewRoot; 32 | this.config = config; 33 | this.application = application; 34 | this.layerRoot = layerRoot; 35 | this.rootView = rootView; 36 | renderNode = RenderNodeCompact.create(getClass().getName()); 37 | onAttach(getRootView()); 38 | } 39 | 40 | // 41 | // private final Canvas requireCanvas() { 42 | // return CanvasHolder.requireCanvasFor(viewRootImpl); 43 | // } 44 | // 45 | // private final void releaseCanvas() { 46 | // CanvasHolder.releaseCanvasFor(viewRootImpl); 47 | // } 48 | 49 | protected void invalidate() { 50 | // renderNode.setLeftTopRightBottom(0, 0, getRootView().getWidth(), getRootView().getHeight()); 51 | // DisplayListCanvas displayListCanvas = renderNode.start(getRootView().getWidth(), getRootView().getHeight()); 52 | // onDraw(displayListCanvas); 53 | // renderNode.end(displayListCanvas); 54 | View view = getRootView(); 55 | if (view == null) { 56 | return; 57 | } 58 | Canvas canvas = renderNode.beginRecording(view.getWidth(), view.getHeight()); 59 | draw(canvas); 60 | renderNode.endRecording(canvas); 61 | layerRoot.invalidate(); 62 | } 63 | 64 | private void draw(Canvas canvas) { 65 | if (isEnable == false) { 66 | canvas.drawColor(0); 67 | return; 68 | } 69 | onDraw(canvas); 70 | } 71 | 72 | public final boolean isEnable() { 73 | return isEnable; 74 | } 75 | 76 | public final void enable(boolean enable) { 77 | isEnable = enable; 78 | invalidate(); 79 | onEnableChange(enable); 80 | } 81 | 82 | protected void onEnableChange(boolean enable) { 83 | } 84 | 85 | protected void onDraw(Canvas canvas) { 86 | 87 | } 88 | 89 | @Override 90 | public final void beforeTraversal(View rootView) { 91 | onBeforeTraversal(rootView); 92 | } 93 | 94 | @Override 95 | public final void afterTraversal(View rootView) { 96 | onAfterTraversal(rootView); 97 | } 98 | 99 | @Override 100 | public final boolean beforeInputEvent(View rootView, InputEvent event) { 101 | //rootView.invalidate(); 102 | return onBeforeInputEvent(rootView, event); 103 | } 104 | 105 | @Override 106 | public final void afterInputEvent(View rootView, InputEvent event) { 107 | //rootView.invalidate(); 108 | onAfterInputEvent(rootView, event); 109 | } 110 | 111 | protected View getRootView() { 112 | return rootView; 113 | } 114 | 115 | protected void onBeforeTraversal(View rootView) { 116 | } 117 | 118 | protected void onAfterTraversal(View rootView) { 119 | } 120 | 121 | protected boolean onBeforeInputEvent(View rootView, InputEvent event) { 122 | return false; 123 | } 124 | 125 | protected void onAfterInputEvent(View rootView, InputEvent event) { 126 | } 127 | 128 | protected void onAttach(View rootView) { 129 | 130 | } 131 | 132 | protected Application getContext() { 133 | return application; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/adapter/LayerAdapter.java: -------------------------------------------------------------------------------- 1 | //package com.wanjian.sak.layer.adapter; 2 | // 3 | //import android.content.Context; 4 | //import android.graphics.Canvas; 5 | //import android.graphics.Region; 6 | //import android.view.View; 7 | //import android.view.ViewGroup; 8 | // 9 | //import com.wanjian.sak.layer.AbsLayer; 10 | // 11 | // 12 | ///** 13 | // * Created by wanjian on 2016/10/23. 14 | // */ 15 | // 16 | //public abstract class LayerAdapter extends AbsLayer { 17 | // private int mStartLayer; 18 | // private int mEndLayer; 19 | // private boolean isClip; 20 | // 21 | // public LayerAdapter(Context context) { 22 | // super(context); 23 | // } 24 | // 25 | // @Override 26 | // protected void onUiUpdate(Canvas canvas, View rootView) { 27 | // mStartLayer = getStartRange(); 28 | // mEndLayer = getEndRange(); 29 | // isClip = isClipDraw(); 30 | // layerCount(canvas, rootView, 0); 31 | // } 32 | // 33 | // 34 | // private void layerCount(Canvas canvas, View view, int curLayer) { 35 | // if (!getViewFilter().filter(view)) { 36 | // return; 37 | // } 38 | // if (curLayer > mEndLayer) { 39 | // return; 40 | // } 41 | // canvas.save(); 42 | // if (curLayer >= mStartLayer) { 43 | // drawLayer(canvas, view, curLayer); 44 | // } 45 | // if (!(view instanceof ViewGroup)) { 46 | // canvas.restore(); 47 | // return; 48 | // } 49 | // 50 | // clipIfNeeded(canvas, view, curLayer); 51 | // 52 | // ViewGroup vg = ((ViewGroup) view); 53 | // for (int i = 0, len = vg.getChildCount(); i < len; i++) { 54 | // View child = vg.getChildAt(i); 55 | // layerCount(canvas, child, curLayer + 1); 56 | // } 57 | // 58 | // canvas.restore(); 59 | // } 60 | // 61 | // private void clipIfNeeded(Canvas canvas, View view, int curLayer) { 62 | // if (!isClip) { 63 | // return; 64 | // } 65 | // 66 | // int w = view.getWidth(); 67 | // int h = view.getHeight(); 68 | // canvas.clipRect(0 69 | // , 0 70 | // , w 71 | // , h 72 | // , Region.Op.INTERSECT); 73 | // } 74 | // 75 | // 76 | // private void drawLayer(Canvas canvas, View view, int curLayer) { 77 | // int pl = 0; 78 | // int pt = 0; 79 | // if (curLayer == 1) { 80 | // View decorView = (View) view.getParent(); 81 | // pl = decorView.getPaddingLeft(); 82 | // pt = decorView.getPaddingTop(); 83 | // }//view.getLocationInWindow(); 84 | // canvas.translate(view.getX() - pl - view.getScrollX(), view.getY() - pt - view.getScrollY()); 85 | // int count = canvas.save(); 86 | // onDrawLayer(canvas, view); 87 | // canvas.restoreToCount(count); 88 | // } 89 | // 90 | // protected abstract void onDrawLayer(Canvas canvas, View view); 91 | //} 92 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/adapter/LayerTxtAdapter.java: -------------------------------------------------------------------------------- 1 | //package com.wanjian.sak.layer.adapter; 2 | // 3 | //import android.content.Context; 4 | //import android.graphics.Canvas; 5 | //import android.graphics.Color; 6 | //import android.graphics.Paint; 7 | //import android.graphics.Rect; 8 | //import android.view.View; 9 | // 10 | ///** 11 | // * Created by wanjian on 2016/10/26. 12 | // *

13 | // * 在view左上角画浅白色背景和文本 14 | // */ 15 | // 16 | //public abstract class LayerTxtAdapter extends LayerAdapter { 17 | // private final Paint mPaint; 18 | // private Rect mRect = new Rect(); 19 | // 20 | // public LayerTxtAdapter(Context context) { 21 | // super(context); 22 | // mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 23 | // mPaint.setTextSize(dp2px(10)); 24 | // mPaint.setColor(getColor()); 25 | // } 26 | // 27 | // 28 | // @Override 29 | // protected void onDrawLayer(Canvas canvas, View view) { 30 | // String txt = getTxt(view); 31 | // if (txt == null) { 32 | // txt = ""; 33 | // } 34 | // drawTxt(txt, canvas, view); 35 | // } 36 | // 37 | // protected abstract String getTxt(View view); 38 | // 39 | // private void drawTxt(String txt, Canvas canvas, View view) { 40 | // mPaint.setTextSize(getTextSize()); 41 | // mPaint.getTextBounds(txt, 0, txt.length(), mRect); 42 | // mPaint.setColor(getBackgroundColor()); 43 | // canvas.drawRect(0, 0, mRect.width() + 2, mRect.height() + 2, mPaint); 44 | // mPaint.setColor(getColor()); 45 | // canvas.drawText(txt, 1, 1 + mRect.height(), mPaint); 46 | // } 47 | // 48 | // protected int getColor() { 49 | // return Color.BLACK; 50 | // } 51 | // 52 | // protected int getBackgroundColor() { 53 | // return 0x88ffffff; 54 | // } 55 | // 56 | // public float getTextSize() { 57 | // return dp2px(10); 58 | // } 59 | //} 60 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/ActivityNameLayerView.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.drawable.Drawable; 8 | import android.text.Layout; 9 | import android.text.SpannableString; 10 | import android.text.Spanned; 11 | import android.text.StaticLayout; 12 | import android.text.TextPaint; 13 | import android.text.style.BackgroundColorSpan; 14 | import android.view.View; 15 | 16 | import com.wanjian.sak.R; 17 | import com.wanjian.sak.layer.Layer; 18 | import com.wanjian.sak.utils.ScreenUtils; 19 | import com.wanjian.sak.utils.Utils; 20 | 21 | public class ActivityNameLayerView extends Layer { 22 | 23 | private Paint mPaint; 24 | private String mActName; 25 | private int mRadius; 26 | 27 | @Override 28 | protected void onAttach(View rootView) { 29 | super.onAttach(rootView); 30 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 31 | mPaint.setTextSize(ScreenUtils.dp2px(getContext(), 10)); 32 | mPaint.setColor(Color.RED); 33 | mPaint.setStrokeWidth(ScreenUtils.dp2px(getContext(), 1)); 34 | mRadius = ScreenUtils.dp2px(getContext(), 8); 35 | getActivityName(rootView); 36 | } 37 | 38 | protected void getActivityName(View view) { 39 | Activity activity = Utils.findAct(view); 40 | if (activity == null) { 41 | return; 42 | } 43 | mActName = activity.getClass().getName(); 44 | invalidate(); 45 | } 46 | 47 | @Override 48 | protected void onDraw(Canvas canvas) { 49 | super.onDraw(canvas); 50 | drawActivityInfo(canvas); 51 | } 52 | 53 | protected void drawActivityInfo(Canvas canvas) { 54 | if (mActName == null) { 55 | return; 56 | } 57 | drawInfo(canvas, 0, 0, canvas.getWidth(), canvas.getHeight(), mActName); 58 | } 59 | 60 | 61 | protected void drawInfo(Canvas canvas, int x, int y, int w, int h, String txt) { 62 | canvas.save(); 63 | drawCorner(canvas, x, y, w, h); 64 | 65 | drawX(canvas, x, y, w, h); 66 | 67 | drawName(canvas, x, y, w, h, txt); 68 | canvas.restore(); 69 | } 70 | 71 | private void drawName(Canvas canvas, int x, int y, int w, int h, String txt) { 72 | TextPaint textPaint = new TextPaint(mPaint); 73 | textPaint.setTextSize(ScreenUtils.dp2px(getContext(), 13)); 74 | canvas.translate(x, y); 75 | SpannableString decorStr = new SpannableString(txt); 76 | decorStr.setSpan(new BackgroundColorSpan(0x99FFFFFF), 0, txt.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 77 | StaticLayout staticLayout = new StaticLayout(decorStr, textPaint, (int) (w * 0.8), Layout.Alignment.ALIGN_CENTER, 1, 0, false); 78 | 79 | int txtW = staticLayout.getWidth(); 80 | int txtH = staticLayout.getHeight(); 81 | if (txtH > 0 && txtH > h * 0.8) { 82 | float scale = h * 0.8f / txtH; 83 | int realW = (int) (txtW * scale); 84 | int realH = (int) (txtH * scale); 85 | 86 | canvas.translate((w - realW) / 2f, (h - realH) / 2f); 87 | canvas.scale(scale, scale); 88 | } else { 89 | canvas.translate((w - txtW) / 2f, (h - txtH) / 2f); 90 | } 91 | 92 | staticLayout.draw(canvas); 93 | } 94 | 95 | private void drawX(Canvas canvas, int x, int y, int w, int h) { 96 | canvas.drawLine(x, y, x + w, y + h, mPaint); 97 | canvas.drawLine(x + w, y, x, y + h, mPaint); 98 | } 99 | 100 | private void drawCorner(Canvas canvas, int x, int y, int w, int h) { 101 | canvas.drawLine(x, y, x + mRadius, y, mPaint); 102 | canvas.drawLine(x, y, x, y + mRadius, mPaint); 103 | 104 | canvas.drawLine(x + w, y, x + w - mRadius, y, mPaint); 105 | canvas.drawLine(x + w, y, x + w, y + mRadius, mPaint); 106 | 107 | 108 | canvas.drawLine(x, y + h, x + mRadius, y + h, mPaint); 109 | canvas.drawLine(x, y + h, x, y + h - mRadius, mPaint); 110 | 111 | 112 | canvas.drawLine(x + w, y + h, x + w - mRadius, y + h, mPaint); 113 | canvas.drawLine(x + w, y + h, x + w, y + h - mRadius, mPaint); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/BackgroundColorLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.graphics.drawable.ColorDrawable; 4 | import android.graphics.drawable.Drawable; 5 | import android.graphics.drawable.ShapeDrawable; 6 | import android.view.View; 7 | 8 | import static android.os.Build.VERSION.SDK_INT; 9 | 10 | /** 11 | * Created by wanjian on 2016/10/26. 12 | */ 13 | 14 | public class BackgroundColorLayer extends LayerTxtAdapter { 15 | 16 | @Override 17 | protected String getTxt(View view) { 18 | if (SDK_INT < 11) { 19 | return ""; 20 | } 21 | Drawable drawable = view.getBackground(); 22 | if (drawable != null) { 23 | drawable = drawable.getCurrent(); 24 | } 25 | if (drawable instanceof ColorDrawable) { 26 | int color = ((ColorDrawable) drawable).getColor(); 27 | String txt = String.format("#%08x", color); 28 | return txt; 29 | } else if (drawable instanceof ShapeDrawable) { 30 | } 31 | 32 | return ""; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/BitmapWidthHeightLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.drawable.BitmapDrawable; 6 | import android.graphics.drawable.Drawable; 7 | import android.view.View; 8 | import android.widget.ImageView; 9 | 10 | import com.wanjian.sak.converter.ISizeConverter; 11 | import com.wanjian.sak.layer.ISize; 12 | 13 | 14 | /** 15 | * 16 | */ 17 | 18 | public class BitmapWidthHeightLayer extends LayerTxtAdapter implements ISize { 19 | private ISizeConverter sizeConverter = ISizeConverter.CONVERTER; 20 | 21 | @Override 22 | protected String getTxt(View view) { 23 | ISizeConverter converter = sizeConverter; 24 | Context context = getContext(); 25 | if (view instanceof ImageView) { 26 | Drawable drawable = ((ImageView) view).getDrawable(); 27 | if (drawable instanceof BitmapDrawable) { 28 | Bitmap bmp = ((BitmapDrawable) drawable).getBitmap(); 29 | if (bmp != null && !bmp.isRecycled()) { 30 | return (int) converter.convert(context, bmp.getWidth()).getLength() + ":" + (int) converter.convert(context, bmp.getHeight()).getLength(); 31 | } 32 | } 33 | } 34 | return ""; 35 | } 36 | 37 | 38 | @Override 39 | public void onSizeConvertChange(ISizeConverter converter) { 40 | sizeConverter = converter; 41 | invalidate(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/BorderLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.Paint; 6 | import android.graphics.drawable.Drawable; 7 | import android.view.View; 8 | 9 | import com.wanjian.sak.R; 10 | import com.wanjian.sak.utils.ScreenUtils; 11 | 12 | 13 | /** 14 | * Created by wanjian on 2016/10/24. 15 | */ 16 | 17 | public class BorderLayer extends ViewLayer { 18 | 19 | private Paint mBorderPaint; 20 | private Paint mCornerPaint; 21 | private int mCornerW; 22 | 23 | private int w; 24 | private int h; 25 | 26 | @Override 27 | protected void onAttach(View rootView) { 28 | super.onAttach(rootView); 29 | mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 30 | mBorderPaint.setStyle(Paint.Style.STROKE); 31 | mBorderPaint.setColor(getBorderColor()); 32 | 33 | mCornerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 34 | mCornerPaint.setStyle(Paint.Style.STROKE); 35 | mCornerPaint.setStrokeWidth(ScreenUtils.dp2px(getContext(), 1)); 36 | mCornerPaint.setColor(getCornerColor()); 37 | 38 | mCornerW = ScreenUtils.dp2px(getContext(), 6); 39 | // invalidate(); 40 | } 41 | 42 | @Override 43 | protected void onDraw(Canvas canvas, View view) { 44 | w = view.getWidth(); 45 | h = view.getHeight(); 46 | drawBorder(canvas); 47 | drawCorner(canvas); 48 | } 49 | 50 | protected int getBorderColor() { 51 | return getContext().getResources().getColor(R.color.sak_color_primary); 52 | } 53 | 54 | protected int getCornerColor() { 55 | return Color.MAGENTA; 56 | } 57 | 58 | private void drawBorder(Canvas canvas) { 59 | canvas.drawRect(0, 0, w, h, mBorderPaint); 60 | } 61 | 62 | private void drawCorner(Canvas canvas) { 63 | //-- 64 | canvas.drawLine(0, 0, mCornerW, 0, mCornerPaint); 65 | //| 66 | canvas.drawLine(0, 0, 0, mCornerW, mCornerPaint); 67 | // -- 68 | canvas.drawLine(w - mCornerW, 0, w, 0, mCornerPaint); 69 | // | 70 | canvas.drawLine(w, 0, w, mCornerW, mCornerPaint); 71 | // 72 | canvas.drawLine(0, h, 0, h - mCornerW, mCornerPaint); 73 | canvas.drawLine(0, h, mCornerW, h, mCornerPaint); 74 | 75 | canvas.drawLine(w - mCornerW, h, w, h, mCornerPaint); 76 | canvas.drawLine(w, h - mCornerW, w, h, mCornerPaint); 77 | 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/FlashWindowLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.graphics.Canvas; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.view.View; 7 | 8 | import com.wanjian.sak.layer.Layer; 9 | import com.wanjian.sak.system.canvaspool.CanvasPoolCompact; 10 | import com.wanjian.sak.system.canvaspool.CanvasRecycleListener; 11 | 12 | public class FlashWindowLayer extends Layer { 13 | private CanvasRecycleListener listener = new CanvasRecycleListener() { 14 | @Override 15 | public void onRecycle(Canvas canvas) { 16 | if (traversaling == false || flash) { 17 | return; 18 | } 19 | flash(); 20 | } 21 | }; 22 | private Handler handler = new Handler(Looper.getMainLooper()); 23 | private boolean flash; 24 | 25 | private void flash() { 26 | flash = true; 27 | handler.post(new Runnable() { 28 | @Override 29 | public void run() { 30 | invalidate(); 31 | } 32 | }); 33 | handler.postDelayed(new Runnable() { 34 | @Override 35 | public void run() { 36 | flash = false; 37 | } 38 | }, 1000); 39 | } 40 | 41 | @Override 42 | protected void onDraw(Canvas canvas) { 43 | super.onDraw(canvas); 44 | if (flash == false) { 45 | return; 46 | } 47 | int color = 0x88000000 | (int) (Math.random() * 0xFFFFFF); 48 | canvas.drawColor(color); 49 | handler.post(new Runnable() { 50 | @Override 51 | public void run() { 52 | invalidate(); 53 | } 54 | }); 55 | } 56 | 57 | private boolean traversaling; 58 | 59 | @Override 60 | protected void onBeforeTraversal(View rootView) { 61 | super.onBeforeTraversal(rootView); 62 | traversaling = true; 63 | } 64 | 65 | @Override 66 | protected void onAfterTraversal(View rootView) { 67 | super.onAfterTraversal(rootView); 68 | traversaling = false; 69 | } 70 | 71 | @Override 72 | protected void onEnableChange(boolean enable) { 73 | super.onEnableChange(enable); 74 | if (enable) { 75 | CanvasPoolCompact.get().registerListener(listener); 76 | } else { 77 | CanvasPoolCompact.get().removeListener(listener); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/GridLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.Paint; 6 | import android.graphics.drawable.Drawable; 7 | import android.view.View; 8 | 9 | import com.wanjian.sak.R; 10 | import com.wanjian.sak.layer.Layer; 11 | import com.wanjian.sak.utils.ScreenUtils; 12 | 13 | public class GridLayer extends Layer { 14 | 15 | private Paint mPaint; 16 | 17 | @Override 18 | protected void onAttach(View rootView) { 19 | super.onAttach(rootView); 20 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 21 | mPaint.setColor(color()); 22 | invalidate(); 23 | } 24 | 25 | @Override 26 | protected void onEnableChange(boolean enable) { 27 | super.onEnableChange(enable); 28 | 29 | } 30 | 31 | @Override 32 | protected void onDraw(Canvas canvas) { 33 | super.onDraw(canvas); 34 | 35 | int w = getRootView().getWidth(); 36 | int h = getRootView().getHeight(); 37 | int space = space(); 38 | 39 | for (int i = space; i < w; i += space) { 40 | canvas.drawLine(i, 0, i, h, mPaint); 41 | } 42 | for (int i = space; i < h; i += space) { 43 | canvas.drawLine(0, i, w, i, mPaint); 44 | } 45 | } 46 | 47 | 48 | @Override 49 | protected void onAfterTraversal(View rootView) { 50 | invalidate(); 51 | } 52 | 53 | protected int color() { 54 | return 0x55000000; 55 | } 56 | 57 | protected int space() { 58 | return ScreenUtils.dp2px(getContext(), 5); 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/HorizontalMeasureView.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.Paint; 6 | import android.graphics.Rect; 7 | import android.view.InputEvent; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | 11 | import com.wanjian.sak.converter.ISizeConverter; 12 | import com.wanjian.sak.layer.ISize; 13 | import com.wanjian.sak.layer.Layer; 14 | import com.wanjian.sak.utils.ScreenUtils; 15 | 16 | 17 | /** 18 | * Created by wanjian on 2016/11/10. 19 | */ 20 | 21 | public class HorizontalMeasureView extends Layer implements ISize { 22 | protected Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 23 | protected int m20DP; 24 | protected int maxHeight; 25 | protected int minHeight; 26 | private int height; 27 | private boolean consume; 28 | private float lastX, lastY; 29 | private Rect rect = new Rect(); 30 | 31 | @Override 32 | protected void onAttach(View rootView) { 33 | super.onAttach(rootView); 34 | init(); 35 | } 36 | 37 | 38 | private void init() { 39 | mPaint.setColor(Color.BLACK); 40 | m20DP = ScreenUtils.dp2px(getContext(), 20); 41 | mPaint.setTextSize(ScreenUtils.dp2px(getContext(), 8)); 42 | maxHeight = ScreenUtils.dp2px(getContext(), 10); 43 | minHeight = ScreenUtils.dp2px(getContext(), 5); 44 | height = ScreenUtils.dp2px(getContext(), 60); 45 | rect.left = 0; 46 | rect.top = (int) (getRootView().getHeight() / 2f - height / 2f); 47 | rect.right = getRootView().getWidth(); 48 | rect.bottom = (int) (getRootView().getHeight() / 2f + height / 2f); 49 | invalidate(); 50 | } 51 | 52 | @Override 53 | protected void onAfterTraversal(View rootView) { 54 | super.onAfterTraversal(rootView); 55 | invalidate(); 56 | } 57 | 58 | @Override 59 | protected boolean onBeforeInputEvent(View rootView, InputEvent event) { 60 | if (!(event instanceof MotionEvent)) { 61 | return false; 62 | } 63 | MotionEvent motionEvent = ((MotionEvent) event); 64 | if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) { 65 | lastX = motionEvent.getX(); 66 | lastY = motionEvent.getY(); 67 | if (rect.contains((int) lastX, (int) lastY)) { 68 | consume = true; 69 | } else { 70 | consume = false; 71 | } 72 | } 73 | if (consume == false) { 74 | return false; 75 | } 76 | float curX = motionEvent.getX(); 77 | float curY = motionEvent.getY(); 78 | 79 | int dx = (int) (curX - lastX); 80 | int dy = (int) (curY - lastY); 81 | rect.left += dx; 82 | rect.right += dx; 83 | rect.top += dy; 84 | rect.bottom += dy; 85 | invalidate(); 86 | lastX = curX; 87 | lastY = curY; 88 | return true; 89 | } 90 | 91 | @Override 92 | protected void onDraw(Canvas canvas) { 93 | super.onDraw(canvas); 94 | canvas.translate(rect.left, rect.top); 95 | mPaint.setStyle(Paint.Style.FILL); 96 | mPaint.setColor(0xbbFFFFFF); 97 | canvas.drawRect(0, 0, rect.right - rect.left, rect.bottom - rect.top, mPaint); 98 | mPaint.setStyle(Paint.Style.STROKE); 99 | mPaint.setColor(Color.BLACK); 100 | canvas.drawRect(0, 0, rect.right - rect.left, rect.bottom - rect.top, mPaint); 101 | mPaint.setStyle(Paint.Style.FILL); 102 | int w = rect.right - rect.left; 103 | canvas.drawLine(0, 0, w, 0, mPaint); 104 | for (int i = 0; i <= w; i += m20DP) { 105 | canvas.drawLine(i, -maxHeight, i, maxHeight , mPaint); 106 | canvas.rotate(90, i, maxHeight); 107 | canvas.drawText(sizeConverter.convert(getContext(), i).toString(), i, maxHeight, mPaint); 108 | canvas.rotate(-90, i, maxHeight); 109 | for (int j = i; j <= w && j < i + m20DP; j += m20DP / 10) { 110 | canvas.drawLine(j, -minHeight, j, minHeight, mPaint); 111 | } 112 | } 113 | } 114 | 115 | ISizeConverter sizeConverter = ISizeConverter.CONVERTER; 116 | 117 | @Override 118 | public void onSizeConvertChange(ISizeConverter converter) { 119 | sizeConverter = converter; 120 | invalidate(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/LayerTxtAdapter.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.Paint; 6 | import android.graphics.Rect; 7 | import android.view.View; 8 | 9 | import com.wanjian.sak.utils.ScreenUtils; 10 | 11 | /** 12 | * Created by wanjian on 2016/10/26. 13 | *

14 | * 在view左上角画浅白色背景和文本 15 | */ 16 | 17 | public abstract class LayerTxtAdapter extends ViewLayer { 18 | private Paint mPaint; 19 | private Rect mRect = new Rect(); 20 | 21 | @Override 22 | protected void onAttach(View rootView) { 23 | super.onAttach(rootView); 24 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 25 | mPaint.setTextSize(ScreenUtils.dp2px(getContext(), 10)); 26 | mPaint.setColor(getColor()); 27 | } 28 | 29 | @Override 30 | protected void onDraw(Canvas canvas, View view) { 31 | String txt = getTxt(view); 32 | if (txt == null) { 33 | txt = ""; 34 | } 35 | drawTxt(txt, canvas, view); 36 | } 37 | 38 | protected abstract String getTxt(View view); 39 | 40 | private void drawTxt(String txt, Canvas canvas, View view) { 41 | mPaint.setTextSize(getTextSize()); 42 | mPaint.getTextBounds(txt, 0, txt.length(), mRect); 43 | mPaint.setColor(getBackgroundColor()); 44 | canvas.drawRect(0, 0, mRect.width(), mRect.height(), mPaint); 45 | mPaint.setColor(getColor()); 46 | canvas.drawText(txt, 0, mRect.height(), mPaint); 47 | } 48 | 49 | protected int getColor() { 50 | return Color.BLACK; 51 | } 52 | 53 | protected int getBackgroundColor() { 54 | return 0x88ffffff; 55 | } 56 | 57 | public float getTextSize() { 58 | return ScreenUtils.dp2px(getContext(), 10); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/PaddingLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.Rect; 7 | import android.graphics.drawable.Drawable; 8 | import android.view.View; 9 | 10 | import com.wanjian.sak.R; 11 | import com.wanjian.sak.converter.ISizeConverter; 12 | import com.wanjian.sak.layer.ISize; 13 | import com.wanjian.sak.utils.ScreenUtils; 14 | 15 | import java.text.DecimalFormat; 16 | 17 | 18 | /** 19 | * Created by wanjian on 2016/10/23. 20 | */ 21 | 22 | public class PaddingLayer extends ViewLayer implements ISize { 23 | private Paint mTextPaint; 24 | private Paint mBgPaint; 25 | private Paint mPaddingPaint; 26 | private int mTxtColor = 0xFF000000; 27 | private int mBgColor = 0x88FFFFFF; 28 | private int mPaddingColor = 0x3300FF0D; 29 | private Rect mRect = new Rect(); 30 | private DecimalFormat mFormat = new DecimalFormat("#.###"); 31 | 32 | @Override 33 | protected void onAttach(View rootView) { 34 | super.onAttach(rootView); 35 | mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 36 | mTextPaint.setTextSize(ScreenUtils.dp2px(getContext(), 10)); 37 | mTextPaint.setColor(mTxtColor); 38 | 39 | mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 40 | mBgPaint.setColor(mBgColor); 41 | 42 | mPaddingPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 43 | mPaddingPaint.setColor(mPaddingColor); 44 | } 45 | 46 | protected void onDraw(Canvas canvas, View view) { 47 | int l = view.getPaddingLeft(); 48 | int t = view.getPaddingTop(); 49 | int r = view.getPaddingRight(); 50 | int b = view.getPaddingBottom(); 51 | int w = view.getWidth(); 52 | int h = view.getHeight(); 53 | 54 | canvas.drawRect(0, 0, l, h, mPaddingPaint); 55 | canvas.drawRect(0, 0, w, t, mPaddingPaint); 56 | canvas.drawRect(w - r, 0, w, h, mPaddingPaint); 57 | canvas.drawRect(0, h - b, w, h, mPaddingPaint); 58 | 59 | ISizeConverter converter = getSizeConverter(); 60 | Context context = getContext(); 61 | if (l != 0) { 62 | String txt = "L" + mFormat.format(converter.convert(context, l).getLength()); 63 | mTextPaint.getTextBounds(txt, 0, txt.length(), mRect); 64 | canvas.drawRect(0, h / 2f - mRect.height() / 2f, mRect.width(), h / 2f + mRect.height() / 2f, mBgPaint); 65 | canvas.drawText(txt, 0, h / 2f + mRect.height() / 2f, mTextPaint); 66 | } 67 | if (t != 0) { 68 | String txt = "T" + mFormat.format(converter.convert(context, t).getLength()); 69 | mTextPaint.getTextBounds(txt, 0, txt.length(), mRect); 70 | canvas.drawRect(w / 2f - mRect.width() / 2f, 0, w / 2f + mRect.width() / 2f, mRect.height(), mBgPaint); 71 | canvas.drawText(txt, w / 2f - mRect.width() / 2f, mRect.height(), mTextPaint); 72 | } 73 | if (r != 0) { 74 | String txt = "R" + mFormat.format(converter.convert(context, r).getLength()); 75 | mTextPaint.getTextBounds(txt, 0, txt.length(), mRect); 76 | canvas.drawRect(w - mRect.width(), h / 2f - mRect.height() / 2f, w, h / 2f + mRect.height() / 2f, mBgPaint); 77 | canvas.drawText(txt, w - mRect.width(), h / 2f + mRect.height() / 2f, mTextPaint); 78 | } 79 | if (b != 0) { 80 | String txt = "B" + mFormat.format(converter.convert(context, b).getLength()); 81 | mTextPaint.getTextBounds(txt, 0, txt.length(), mRect); 82 | canvas.drawRect(w / 2f - mRect.width() / 2f, h - mRect.height(), w / 2f + mRect.width() / 2f, h, mBgPaint); 83 | canvas.drawText(txt, w / 2f - mRect.width() / 2f, h, mTextPaint); 84 | } 85 | } 86 | 87 | 88 | private ISizeConverter getSizeConverter() { 89 | return sizeConverter == null ? ISizeConverter.CONVERTER : sizeConverter; 90 | } 91 | 92 | private ISizeConverter sizeConverter; 93 | 94 | @Override 95 | public void onSizeConvertChange(ISizeConverter converter) { 96 | sizeConverter = converter; 97 | invalidate(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/TextColorLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.graphics.drawable.Drawable; 4 | import android.text.SpannableString; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | import com.wanjian.sak.R; 9 | 10 | 11 | /** 12 | * Created by wanjian on 2016/10/26. 13 | */ 14 | 15 | public class TextColorLayer extends LayerTxtAdapter { 16 | 17 | 18 | @Override 19 | protected String getTxt(View view) { 20 | if (view instanceof TextView) { 21 | CharSequence charSequence = ((TextView) view).getText(); 22 | if (charSequence instanceof SpannableString) { 23 | // TODO: 2019/2/17 24 | } 25 | int color = ((TextView) view).getCurrentTextColor(); 26 | return String.format("#%08x", color); 27 | 28 | } 29 | return ""; 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/TextSizeLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.graphics.drawable.Drawable; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.wanjian.sak.R; 8 | import com.wanjian.sak.converter.ISizeConverter; 9 | import com.wanjian.sak.layer.ISize; 10 | 11 | 12 | /** 13 | * Created by wanjian on 2016/10/26. 14 | */ 15 | 16 | public class TextSizeLayer extends LayerTxtAdapter implements ISize { 17 | @Override 18 | protected String getTxt(View view) { 19 | if (view instanceof TextView) { 20 | float size = ((TextView) view).getTextSize(); 21 | return String.valueOf(getSizeConverter().convert(getContext(), size).getLength()); 22 | } 23 | 24 | return ""; 25 | } 26 | 27 | 28 | 29 | private ISizeConverter getSizeConverter() { 30 | return sizeConverter == null ? ISizeConverter.CONVERTER : sizeConverter; 31 | } 32 | 33 | private ISizeConverter sizeConverter; 34 | 35 | @Override 36 | public void onSizeConvertChange(ISizeConverter converter) { 37 | sizeConverter = converter; 38 | invalidate(); 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/VerticalMeasureView.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.Paint; 6 | import android.graphics.Rect; 7 | import android.view.InputEvent; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | 11 | import com.wanjian.sak.converter.ISizeConverter; 12 | import com.wanjian.sak.layer.ISize; 13 | import com.wanjian.sak.layer.Layer; 14 | import com.wanjian.sak.utils.ScreenUtils; 15 | 16 | 17 | /** 18 | * Created by wanjian on 2016/11/10. 19 | */ 20 | 21 | public class VerticalMeasureView extends Layer implements ISize { 22 | protected Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 23 | protected int m20DP; 24 | protected int maxHeight; 25 | protected int minHeight; 26 | private int width; 27 | private boolean consume; 28 | private float lastX, lastY; 29 | private Rect rect = new Rect(); 30 | 31 | @Override 32 | protected void onAttach(View rootView) { 33 | super.onAttach(rootView); 34 | init(); 35 | } 36 | 37 | 38 | private void init() { 39 | mPaint.setColor(Color.BLACK); 40 | m20DP = ScreenUtils.dp2px(getContext(), 20); 41 | mPaint.setTextSize(ScreenUtils.dp2px(getContext(), 8)); 42 | maxHeight = ScreenUtils.dp2px(getContext(), 10); 43 | minHeight = ScreenUtils.dp2px(getContext(), 5); 44 | width = ScreenUtils.dp2px(getContext(), 60); 45 | rect.left = (int) (getRootView().getWidth() / 2f - width / 2f); 46 | rect.top = 0; 47 | rect.right = (int) (getRootView().getWidth() / 2f + width / 2f); 48 | rect.bottom = getRootView().getHeight(); 49 | invalidate(); 50 | } 51 | 52 | @Override 53 | protected void onAfterTraversal(View rootView) { 54 | super.onAfterTraversal(rootView); 55 | invalidate(); 56 | } 57 | 58 | @Override 59 | protected boolean onBeforeInputEvent(View rootView, InputEvent event) { 60 | if (!(event instanceof MotionEvent)) { 61 | return false; 62 | } 63 | MotionEvent motionEvent = ((MotionEvent) event); 64 | if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) { 65 | lastX = motionEvent.getX(); 66 | lastY = motionEvent.getY(); 67 | if (rect.contains((int) lastX, (int) lastY)) { 68 | consume = true; 69 | } else { 70 | consume = false; 71 | } 72 | } 73 | if (consume == false) { 74 | return false; 75 | } 76 | float curX = motionEvent.getX(); 77 | float curY = motionEvent.getY(); 78 | 79 | int dx = (int) (curX - lastX); 80 | int dy = (int) (curY - lastY); 81 | rect.left += dx; 82 | rect.right += dx; 83 | rect.top += dy; 84 | rect.bottom += dy; 85 | invalidate(); 86 | lastX = curX; 87 | lastY = curY; 88 | return true; 89 | } 90 | 91 | @Override 92 | protected void onDraw(Canvas canvas) { 93 | super.onDraw(canvas); 94 | canvas.translate(rect.left, rect.top); 95 | mPaint.setStyle(Paint.Style.FILL); 96 | mPaint.setColor(0xbbFFFFFF); 97 | canvas.drawRect(0, 0, rect.right - rect.left, rect.bottom - rect.top, mPaint); 98 | mPaint.setStyle(Paint.Style.STROKE); 99 | mPaint.setColor(Color.BLACK); 100 | canvas.drawRect(0, 0, rect.right - rect.left, rect.bottom - rect.top, mPaint); 101 | mPaint.setStyle(Paint.Style.FILL); 102 | int h = rect.bottom - rect.top; 103 | int w = rect.right - rect.left; 104 | canvas.drawLine(0, 0, w, 0, mPaint); 105 | 106 | for (int i = 0; i <= h; i += m20DP) { 107 | canvas.drawLine(-maxHeight, i, maxHeight, i, mPaint); 108 | canvas.drawText(sizeConverter.convert(getContext(), i).toString(), maxHeight, i, mPaint); 109 | for (int j = i; j <= h && j < i + m20DP; j += m20DP / 10) { 110 | canvas.drawLine(-minHeight, j, minHeight, j, mPaint); 111 | } 112 | } 113 | } 114 | 115 | ISizeConverter sizeConverter = ISizeConverter.CONVERTER; 116 | 117 | @Override 118 | public void onSizeConvertChange(ISizeConverter converter) { 119 | sizeConverter = converter; 120 | invalidate(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/ViewClassLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.view.View; 6 | 7 | import com.wanjian.sak.R; 8 | 9 | /** 10 | * Created by wanjian on 2017/3/9. 11 | */ 12 | 13 | public class ViewClassLayer extends LayerTxtAdapter { 14 | 15 | 16 | @Override 17 | protected String getTxt(View view) { 18 | return view.getClass().getSimpleName(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/ViewLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Region; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import com.wanjian.sak.layer.IClip; 9 | import com.wanjian.sak.layer.IRange; 10 | import com.wanjian.sak.layer.Layer; 11 | 12 | public abstract class ViewLayer extends Layer implements IRange, IClip { 13 | private int mStartLayer; 14 | private int mEndLayer = 100; 15 | private boolean isClip = true; 16 | 17 | @Override 18 | public void onStartRangeChange(int start) { 19 | mStartLayer = start; 20 | invalidate(); 21 | } 22 | 23 | @Override 24 | public void onEndRangeChange(int end) { 25 | mEndLayer = end; 26 | invalidate(); 27 | } 28 | 29 | @Override 30 | public void onClipChange(boolean clip) { 31 | isClip = clip; 32 | invalidate(); 33 | } 34 | 35 | @Override 36 | protected void onAttach(View rootView) { 37 | super.onAttach(rootView); 38 | } 39 | 40 | @Override 41 | protected final void onDraw(Canvas canvas) { 42 | super.onDraw(canvas); 43 | traversals(canvas, getRootView(), 0); 44 | } 45 | 46 | @Override 47 | protected void onAfterTraversal(View rootView) { 48 | super.onAfterTraversal(rootView); 49 | invalidate(); 50 | } 51 | 52 | // 53 | // public void setStartLayer(int startLayer) { 54 | // this.mStartLayer = startLayer; 55 | // } 56 | // 57 | // public void setEndLayer(int endLayer) { 58 | // this.mEndLayer = endLayer; 59 | // } 60 | 61 | // public void setClip(boolean clip) { 62 | // isClip = clip; 63 | // } 64 | 65 | private void traversals(Canvas canvas, View view, int curLayer) { 66 | if (curLayer > mEndLayer) { 67 | return; 68 | } 69 | if (curLayer >= mStartLayer) { 70 | int count = canvas.save(); 71 | onDraw(canvas, view); 72 | canvas.restoreToCount(count); 73 | } 74 | 75 | if (view instanceof ViewGroup) { 76 | ViewGroup vg = ((ViewGroup) view); 77 | int sx = view.getScrollX(); 78 | int sy = view.getScrollY(); 79 | canvas.save(); //save 1 80 | canvas.translate(-sx, -sy); 81 | 82 | for (int i = 0, len = vg.getChildCount(); i < len; i++) { 83 | View child = vg.getChildAt(i); 84 | canvas.save();//save 2 85 | canvas.translate(child.getX(), child.getY()); 86 | if (isClip) { 87 | canvas.clipRect(0, 0, child.getWidth(), child.getHeight(), Region.Op.INTERSECT); 88 | } 89 | 90 | // canvas.save(); //save 3 91 | traversals(canvas, child, curLayer + 1); 92 | // canvas.restore();// restore 3 93 | 94 | canvas.restore();// restore 2 95 | } 96 | canvas.restore(); // restore 1 97 | } 98 | } 99 | 100 | protected abstract void onDraw(Canvas canvas, View view); 101 | 102 | } 103 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl/WidthHeightLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl; 2 | 3 | import android.graphics.drawable.Drawable; 4 | import android.view.View; 5 | 6 | import com.wanjian.sak.R; 7 | import com.wanjian.sak.converter.ISizeConverter; 8 | import com.wanjian.sak.layer.ISize; 9 | 10 | /** 11 | * 12 | */ 13 | 14 | public class WidthHeightLayer extends LayerTxtAdapter implements ISize { 15 | 16 | 17 | @Override 18 | protected String getTxt(View view) { 19 | int w = view.getWidth(); 20 | int h = view.getHeight(); 21 | ISizeConverter converter = getSizeConverter(); 22 | return converter.convert(getContext(), w).getLength() + ":" + converter.convert(getContext(), h).getLength(); 23 | } 24 | 25 | 26 | private ISizeConverter getSizeConverter() { 27 | return sizeConverter == null ? ISizeConverter.CONVERTER : sizeConverter; 28 | } 29 | 30 | private ISizeConverter sizeConverter; 31 | 32 | @Override 33 | public void onSizeConvertChange(ISizeConverter converter) { 34 | sizeConverter = converter; 35 | invalidate(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl_tmp/CornerMeasureView.java: -------------------------------------------------------------------------------- 1 | //package com.wanjian.sak.layer.impl_tmp; 2 | // 3 | //import android.content.Context; 4 | //import android.graphics.Canvas; 5 | //import android.graphics.Color; 6 | //import android.graphics.Paint; 7 | //import android.graphics.Path; 8 | //import android.graphics.RectF; 9 | //import android.graphics.drawable.Drawable; 10 | //import android.view.ViewGroup; 11 | //import android.widget.FrameLayout; 12 | // 13 | //import com.wanjian.sak.R; 14 | //import com.wanjian.sak.support.DragLayerView; 15 | // 16 | ///** 17 | // * Created by wanjian on 2016/11/10. 18 | // */ 19 | //@Deprecated 20 | //public class CornerMeasureView extends DragLayerView { 21 | // private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 22 | // private int twoDP; 23 | // private int fourDP; 24 | // private int sixDP; 25 | // private int eightDP; 26 | // private int tenDP; 27 | // private int gap; 28 | // private int textSize; 29 | // 30 | // public CornerMeasureView(Context context) { 31 | // super(context); 32 | // init(); 33 | // } 34 | // 35 | // @Override 36 | // public Drawable icon() { 37 | // return getResources().getDrawable(R.drawable.sak_corner_measure_icon); 38 | // } 39 | // 40 | // @Override 41 | // public String description() { 42 | // return getContext().getString(R.string.sak_corner_measure); 43 | // } 44 | // 45 | // private void init() { 46 | // mPaint.setColor(Color.BLACK); 47 | // mPaint.setStyle(Paint.Style.STROKE); 48 | // mPaint.setStrokeWidth(1); 49 | // twoDP = dp2px(2); 50 | // fourDP = dp2px(4); 51 | // sixDP = dp2px(6); 52 | // eightDP = dp2px(8); 53 | // tenDP = dp2px(10); 54 | // gap = dp2px(8); 55 | // textSize = dp2px(6); 56 | // mPaint.setTextSize(textSize); 57 | // } 58 | // 59 | // @Override 60 | // protected void onDraw(Canvas canvas) { 61 | // super.onDraw(canvas); 62 | // 63 | // int w = getWidth(); 64 | // int h = getHeight(); 65 | // mPaint.setStyle(Paint.Style.STROKE); 66 | // drawRound(canvas, 0, 0, w, h, twoDP); 67 | // drawRound(canvas, gap * 1, gap * 1, w - gap * 1, h - gap * 1, fourDP); 68 | // drawRound(canvas, gap * 2, gap * 2, w - gap * 2, h - gap * 2, sixDP); 69 | // drawRound(canvas, gap * 3, gap * 3, w - gap * 3, h - gap * 3, eightDP); 70 | // drawRound(canvas, gap * 4, gap * 4, w - gap * 4, h - gap * 4, tenDP); 71 | // 72 | // 73 | // mPaint.setStyle(Paint.Style.FILL); 74 | // canvas.drawText("2", w / 2, 0, mPaint); 75 | // canvas.drawText("4", w / 2, gap * 1, mPaint); 76 | // canvas.drawText("6", w / 2, gap * 2, mPaint); 77 | // canvas.drawText("8", w / 2, gap * 3, mPaint); 78 | // canvas.drawText("10", w / 2, gap * 4, mPaint); 79 | // 80 | // } 81 | // 82 | // private void drawRound(Canvas canvas, int l, int t, int r, int b, int corner) { 83 | // 84 | // Path path = new Path(); 85 | // path.arcTo(new RectF(l, t, l + corner * 2, t + corner * 2), 180, 90); 86 | // 87 | // path.arcTo(new RectF(r - corner * 2, t, r, t + corner * 2), -90, 90); 88 | // 89 | // path.arcTo(new RectF(r - corner * 2, b - corner * 2, r, b), 0, 90); 90 | // 91 | // path.arcTo(new RectF(l, b - corner * 2, l + corner * 2, b), 90, 90); 92 | // 93 | // path.close(); 94 | // canvas.drawPath(path, mPaint); 95 | // 96 | // } 97 | // 98 | // 99 | // @Override 100 | // public ViewGroup.LayoutParams getLayoutParams(FrameLayout.LayoutParams params) { 101 | // params.width = dp2px(150); 102 | // params.height = dp2px(120); 103 | // return params; 104 | // } 105 | // 106 | //} 107 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/layer/impl_tmp/InfoLayer.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.layer.impl_tmp; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.view.View; 6 | 7 | import com.wanjian.sak.R; 8 | 9 | 10 | /** 11 | * Created by wanjian on 2016/10/24. 12 | */ 13 | @Deprecated 14 | public class InfoLayer { 15 | public static final int INFO_KEY = R.layout.sak_view_info_layout; 16 | 17 | // public InfoLayer(Context context) { 18 | // super(context); 19 | // } 20 | // 21 | // 22 | // @Override 23 | // protected String getTxt(View view) { 24 | // Object obj = view.getTag(INFO_KEY); 25 | // String info; 26 | // if (obj == null) { 27 | // info = ""; 28 | // } else { 29 | // info = obj.toString(); 30 | // } 31 | // return info; 32 | // 33 | // } 34 | // 35 | // @Override 36 | // public Drawable icon() { 37 | // return getContext().getResources().getDrawable(R.drawable.sak_custom_info_icon); 38 | // } 39 | // 40 | // @Override 41 | // public String description() { 42 | // return getContext().getString(R.string.sak_personal_info); 43 | // } 44 | } 45 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/support/DragLayerView.java: -------------------------------------------------------------------------------- 1 | //package com.wanjian.sak.support; 2 | // 3 | //import android.content.Context; 4 | //import android.support.v4.view.GestureDetectorCompat; 5 | //import android.view.GestureDetector; 6 | //import android.view.MotionEvent; 7 | //import android.view.View; 8 | // 9 | //import com.wanjian.sak.layer.AbsLayer; 10 | // 11 | // 12 | ///** 13 | // * Created by wanjian on 2017/2/20. 14 | // */ 15 | // 16 | //public abstract class DragLayerView extends AbsLayer { 17 | // 18 | // private OnTouchListener touchListener; 19 | // 20 | // public DragLayerView(Context context) { 21 | // super(context); 22 | // init(); 23 | // } 24 | // 25 | // private void init() { 26 | // final GestureDetectorCompat detectorCompat = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener() { 27 | // private float lastRowX; 28 | // private float lastRowY; 29 | // 30 | // @Override 31 | // public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 32 | // setTranslationX(getTranslationX() + (e2.getRawX() - lastRowX)); 33 | // setTranslationY(getTranslationY() + (e2.getRawY() - lastRowY)); 34 | // lastRowX = e2.getRawX(); 35 | // lastRowY = e2.getRawY(); 36 | // return true; 37 | // } 38 | // 39 | // @Override 40 | // public boolean onDown(MotionEvent e) { 41 | // lastRowX = e.getRawX(); 42 | // lastRowY = e.getRawY(); 43 | // return true; 44 | // } 45 | // }); 46 | // detectorCompat.setIsLongpressEnabled(false); 47 | // super.setOnTouchListener(new View.OnTouchListener() { 48 | // @Override 49 | // public boolean onTouch(View v, MotionEvent event) { 50 | // boolean b = false; 51 | // if (touchListener != null) { 52 | // b = touchListener.onTouch(v, event); 53 | // } 54 | // return detectorCompat.onTouchEvent(event) || b; 55 | // } 56 | // }); 57 | // } 58 | // 59 | // @Override 60 | // public void setOnTouchListener(OnTouchListener l) { 61 | // touchListener = l; 62 | // } 63 | //} 64 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/support/FPSView.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.support; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.annotation.Nullable; 13 | 14 | import com.wanjian.sak.utils.LoopQueue; 15 | 16 | public class FPSView extends View { 17 | private Paint paint; 18 | private float density; 19 | private Path path = new Path(); 20 | private LoopQueue data; 21 | 22 | public FPSView(@NonNull Context context) { 23 | this(context, null); 24 | } 25 | 26 | public FPSView(@NonNull Context context, @Nullable AttributeSet attrs) { 27 | super(context, attrs); 28 | setWillNotDraw(false); 29 | density = getRootView().getResources().getDisplayMetrics().density; 30 | paint = new Paint(Paint.ANTI_ALIAS_FLAG); 31 | paint.setTextSize(dp2px(10)); 32 | paint.setStyle(Paint.Style.STROKE); 33 | paint.setStrokeWidth(dp2px(0.8f)); 34 | } 35 | 36 | protected int dp2px(float dip) { 37 | return (int) (dip * density + 0.5); 38 | } 39 | 40 | 41 | public void update(LoopQueue data) { 42 | this.data = data; 43 | postInvalidate(); 44 | } 45 | 46 | @Override 47 | protected void onDraw(Canvas canvas) { 48 | super.onDraw(canvas); 49 | if (data == null) { 50 | return; 51 | } 52 | float width = getWidth(); 53 | int height = getHeight(); 54 | float gap = width / (data.maxSize() - 1); 55 | float x = width - gap * data.size(); 56 | 57 | paint.setColor(Color.RED); 58 | path.reset(); 59 | path.moveTo(x, height); 60 | 61 | data.reset(); 62 | while (data.has()) { 63 | float y = -dp2px(data.take()) * 2; 64 | path.lineTo(x, y); 65 | x += gap; 66 | } 67 | canvas.translate(0, height); 68 | canvas.drawPath(path, paint); 69 | 70 | paint.setColor(Color.GREEN); 71 | int dp16 = dp2px(16) * 2; 72 | canvas.drawLine(0, -dp16, width, -dp16, paint); 73 | canvas.drawText("16", 5, -dp16, paint); 74 | 75 | paint.setColor(Color.RED); 76 | int dp30 = dp2px(30) * 2; 77 | canvas.drawLine(0, -dp30, width, -dp30, paint); 78 | canvas.drawText("30", 5, -dp30, paint); 79 | 80 | paint.setColor(Color.MAGENTA); 81 | int dp50 = dp2px(50) * 2; 82 | canvas.drawLine(0, -dp50, width, -dp50, paint); 83 | canvas.drawText("50", 5, -dp50, paint); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/canvas/compact/CanvasCompact.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.canvas.compact; 2 | 3 | import android.graphics.Canvas; 4 | import android.os.Build; 5 | import android.view.ViewRootImpl; 6 | 7 | public abstract class CanvasCompact { 8 | 9 | protected ViewRootImpl viewRootImpl; 10 | 11 | CanvasCompact(ViewRootImpl viewRootImpl) { 12 | this.viewRootImpl = viewRootImpl; 13 | } 14 | 15 | public static CanvasCompact get(ViewRootImpl viewRootImpl) { 16 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { 17 | return new HardwareCanvasV31Impl(viewRootImpl); 18 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 19 | return new HardwareCanvasV29Impl(viewRootImpl); 20 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 21 | return new HardwareCanvasV26Impl(viewRootImpl); 22 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 23 | return new HardwareCanvasV24Impl(viewRootImpl); 24 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 25 | return new HardwareCanvasV23Impl(viewRootImpl); 26 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 27 | return new HardwareCanvasV21Impl(viewRootImpl); 28 | } else { 29 | throw new RuntimeException("unsupport android version"); 30 | } 31 | } 32 | 33 | public abstract Canvas requireCanvas(); 34 | 35 | public abstract void releaseCanvas(); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/canvas/compact/HardwareCanvasV24Impl.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.canvas.compact; 2 | 3 | import android.view.ThreadedRenderer; 4 | import android.view.View; 5 | import android.view.ViewRootImpl; 6 | 7 | import java.lang.reflect.Method; 8 | 9 | public class HardwareCanvasV24Impl extends HardwareCanvasV23Impl { 10 | HardwareCanvasV24Impl(ViewRootImpl viewRootImpl) { 11 | super(viewRootImpl); 12 | } 13 | 14 | protected boolean isThreadRendererEnable(ThreadedRenderer threadRenderer) { 15 | try { 16 | Method isEnabledM = ThreadedRenderer.class.getDeclaredMethod("isEnabled"); 17 | isEnabledM.setAccessible(true); 18 | return (boolean) isEnabledM.invoke(threadRenderer); 19 | } catch (Exception e) { 20 | throw new RuntimeException(e); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/canvas/compact/HardwareCanvasV26Impl.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.canvas.compact; 2 | 3 | import android.view.ThreadedRenderer; 4 | import android.view.View; 5 | import android.view.ViewParent; 6 | import android.view.ViewRootImpl; 7 | 8 | import java.lang.reflect.Field; 9 | 10 | class HardwareCanvasV26Impl extends HardwareCanvasV24Impl { 11 | 12 | HardwareCanvasV26Impl(ViewRootImpl viewRootImpl) { 13 | super(viewRootImpl); 14 | } 15 | 16 | 17 | protected ThreadedRenderer getHardwareRenderer(ViewRootImpl viewRootImpl) { 18 | try { 19 | Field mAttachInfoF = ViewRootImpl.class.getDeclaredField("mAttachInfo"); 20 | mAttachInfoF.setAccessible(true); 21 | Object mAttachInfo = mAttachInfoF.get(viewRootImpl); 22 | Field threadedRendererF; 23 | threadedRendererF = mAttachInfo.getClass().getDeclaredField("mThreadedRenderer"); 24 | threadedRendererF.setAccessible(true); 25 | return (ThreadedRenderer) threadedRendererF.get(mAttachInfo); 26 | } catch (Exception e) { 27 | throw new RuntimeException(e); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/canvas/compact/HardwareCanvasV29Impl.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.canvas.compact; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.FrameInfo; 5 | import android.graphics.HardwareRenderer; 6 | import android.graphics.RecordingCanvas; 7 | import android.graphics.RenderNode; 8 | import android.view.Choreographer; 9 | import android.view.ThreadedRenderer; 10 | import android.view.View; 11 | import android.view.ViewRootImpl; 12 | 13 | import java.lang.reflect.Field; 14 | import java.lang.reflect.Method; 15 | 16 | class HardwareCanvasV29Impl extends HardwareCanvasV26Impl { 17 | private RenderNode mRootNode; 18 | private RecordingCanvas canvas; 19 | private int saveCount; 20 | 21 | HardwareCanvasV29Impl(ViewRootImpl viewRootImpl) { 22 | super(viewRootImpl); 23 | } 24 | 25 | @Override 26 | protected Canvas innerRequire() { 27 | if (threadRenderer != null && isThreadRendererEnable(threadRenderer)) { 28 | markDrawStart(Choreographer.getInstance()); 29 | mRootNode = getRooNodeV29(threadRenderer); 30 | canvas = mRootNode.beginRecording(getSurfaceW(threadRenderer), getSurfaceH(threadRenderer)); 31 | canvas.translate(getInsertLeft(), getInsertTop()); 32 | canvas.translate(-getHardwareXOffset(), -getHardwareYOffset()); 33 | saveCount = canvas.save(); 34 | canvas.enableZ(); 35 | canvas.drawRenderNode(getUpdateDisplayListIfDirty()); 36 | canvas.disableZ(); 37 | return canvas; 38 | } else { 39 | mRootNode = null; 40 | return getSoftCanvas().requireCanvas(); 41 | } 42 | } 43 | 44 | @Override 45 | protected void innerRelease() { 46 | if (mRootNode != null) { 47 | // canvas.disableZ(); 48 | canvas.restoreToCount(saveCount); 49 | mRootNode.endRecording(); 50 | nSyncAndDrawFrame(); 51 | } else { 52 | getSoftCanvas().releaseCanvas(); 53 | } 54 | } 55 | 56 | private RenderNode getUpdateDisplayListIfDirty() { 57 | try { 58 | Method method = View.class.getDeclaredMethod("updateDisplayListIfDirty"); 59 | method.setAccessible(true); 60 | return (RenderNode) method.invoke(viewRootImpl.getView()); 61 | } catch (Exception e) { 62 | throw new RuntimeException(e); 63 | } 64 | } 65 | 66 | protected RenderNode getRooNodeV29(ThreadedRenderer hardwareRenderer) { 67 | try { 68 | Field mRootNodeF = HardwareRenderer.class.getDeclaredField("mRootNode"); 69 | mRootNodeF.setAccessible(true); 70 | return (RenderNode) mRootNodeF.get(hardwareRenderer); 71 | } catch (Exception e) { 72 | throw new RuntimeException(e); 73 | } 74 | } 75 | 76 | @Override 77 | protected void markDrawStart(Choreographer choreographer) { 78 | try { 79 | FrameInfo frameInfo = getFrameInfo(); 80 | frameInfo.markDrawStart(); 81 | } catch (Exception e) { 82 | throw new RuntimeException(e); 83 | } 84 | } 85 | 86 | private FrameInfo getFrameInfo() { 87 | try { 88 | Field mFrameInfoF = Choreographer.class.getDeclaredField("mFrameInfo"); 89 | mFrameInfoF.setAccessible(true); 90 | FrameInfo frameInfo = (FrameInfo) mFrameInfoF.get(Choreographer.getInstance()); 91 | return frameInfo; 92 | } catch (Exception e) { 93 | throw new RuntimeException(e); 94 | } 95 | } 96 | 97 | @Override 98 | protected void nSyncAndDrawFrame() { 99 | // int syncResult = syncAndDrawFrame(choreographer.mFrameInfo); 100 | try { 101 | ThreadedRenderer renderer = getHardwareRenderer(viewRootImpl); 102 | Method method = android.graphics.HardwareRenderer.class.getDeclaredMethod("syncAndDrawFrame", FrameInfo.class); 103 | method.setAccessible(true); 104 | method.invoke(renderer, getFrameInfo()); 105 | } catch (Exception e) { 106 | throw new RuntimeException(e); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/canvas/compact/HardwareCanvasV31Impl.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.canvas.compact; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.FrameInfo; 5 | import android.graphics.HardwareRenderer; 6 | import android.graphics.RecordingCanvas; 7 | import android.graphics.RenderNode; 8 | import android.view.Choreographer; 9 | import android.view.ThreadedRenderer; 10 | import android.view.View; 11 | import android.view.ViewFrameInfo; 12 | import android.view.ViewRootImpl; 13 | 14 | import java.lang.reflect.Field; 15 | import java.lang.reflect.Method; 16 | 17 | class HardwareCanvasV31Impl extends HardwareCanvasV29Impl { 18 | HardwareCanvasV31Impl(ViewRootImpl viewRootImpl) { 19 | super(viewRootImpl); 20 | } 21 | 22 | @Override 23 | protected void markDrawStart(Choreographer choreographer) { 24 | try { 25 | ViewFrameInfo frameInfo = getViewFrameInfo(); 26 | frameInfo.markDrawStart(); 27 | } catch (Exception e) { 28 | throw new RuntimeException(e); 29 | } 30 | } 31 | 32 | private ViewFrameInfo getViewFrameInfo() { 33 | try { 34 | Field mFrameInfoF = ViewRootImpl.class.getDeclaredField("mViewFrameInfo"); 35 | mFrameInfoF.setAccessible(true); 36 | ViewFrameInfo frameInfo = (ViewFrameInfo) mFrameInfoF.get(viewRootImpl); 37 | return frameInfo; 38 | } catch (Exception e) { 39 | throw new RuntimeException(e); 40 | } 41 | } 42 | 43 | private FrameInfo getFrameInfo() { 44 | try { 45 | Method mFrameInfoM = ViewRootImpl.class.getDeclaredMethod("getUpdatedFrameInfo"); 46 | mFrameInfoM.setAccessible(true); 47 | FrameInfo frameInfo = (FrameInfo) mFrameInfoM.invoke(viewRootImpl); 48 | return frameInfo; 49 | } catch (Exception e) { 50 | throw new RuntimeException(e); 51 | } 52 | } 53 | 54 | @Override 55 | protected void nSyncAndDrawFrame() { 56 | try { 57 | ThreadedRenderer renderer = getHardwareRenderer(viewRootImpl); 58 | Method method = HardwareRenderer.class.getDeclaredMethod("syncAndDrawFrame", FrameInfo.class); 59 | method.setAccessible(true); 60 | method.invoke(renderer, getFrameInfo()); 61 | } catch (Exception e) { 62 | throw new RuntimeException(e); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/canvas/compact/SoftCanvas.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.canvas.compact; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | import android.view.Surface; 6 | import android.view.View; 7 | import android.view.ViewRootImpl; 8 | 9 | import java.lang.reflect.Field; 10 | 11 | class SoftCanvas extends CanvasCompact { 12 | 13 | private int count; 14 | private Rect rect = new Rect(); 15 | private Canvas canvas; 16 | private Surface surface; 17 | 18 | SoftCanvas(ViewRootImpl viewRootImpl) { 19 | super(viewRootImpl); 20 | 21 | } 22 | 23 | @Override 24 | public Canvas requireCanvas() { 25 | if (count != 0) { 26 | throw new IllegalStateException("count == " + count); 27 | } 28 | count++; 29 | rect.left = 0; 30 | rect.top = 0; 31 | View rootView = viewRootImpl.getView(); 32 | rect.right = rootView.getWidth(); 33 | rect.bottom = rootView.getHeight(); 34 | canvas = getSurface().lockCanvas(rect); 35 | return canvas; 36 | } 37 | 38 | @Override 39 | public void releaseCanvas() { 40 | if (count != 1) { 41 | throw new IllegalStateException("count == " + count); 42 | } 43 | count--; 44 | getSurface().unlockCanvasAndPost(canvas); 45 | } 46 | 47 | 48 | private Surface getSurface() { 49 | if (surface != null) { 50 | return surface; 51 | } 52 | try { 53 | Field mSurfaceF = ViewRootImpl.class.getDeclaredField("mSurface"); 54 | mSurfaceF.setAccessible(true); 55 | surface = (Surface) mSurfaceF.get(viewRootImpl); 56 | } catch (Exception e) { 57 | throw new RuntimeException(e); 58 | } 59 | return surface; 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/canvaspool/CanvasPoolCompact.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.canvaspool; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.RecordingCanvas; 5 | import android.os.Build; 6 | import android.util.Pools; 7 | import android.view.DisplayListCanvas; 8 | 9 | import java.lang.ref.WeakReference; 10 | import java.lang.reflect.Field; 11 | import java.util.ArrayList; 12 | import java.util.Iterator; 13 | import java.util.List; 14 | 15 | public class CanvasPoolCompact { 16 | private static CanvasPoolCompact sInstance = new CanvasPoolCompact(); 17 | 18 | public static CanvasPoolCompact get() { 19 | return sInstance; 20 | } 21 | 22 | private List> listeners = new ArrayList<>(); 23 | 24 | private CanvasPoolCompact() { 25 | Class clz; 26 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 27 | clz = RecordingCanvas.class; 28 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 29 | clz = DisplayListCanvas.class; 30 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 31 | try { 32 | clz = Class.forName("android.view.GLES20RecordingCanvas"); 33 | } catch (ClassNotFoundException e) { 34 | throw new RuntimeException(e); 35 | } 36 | } else { 37 | throw new RuntimeException(); 38 | } 39 | final Pools.SynchronizedPool origin; 40 | Field field; 41 | try { 42 | field = clz.getDeclaredField("sPool"); 43 | field.setAccessible(true); 44 | origin = (Pools.SynchronizedPool) field.get(null); 45 | } catch (Exception e) { 46 | throw new RuntimeException(e); 47 | } 48 | Pools.SynchronizedPool pool = new Pools.SynchronizedPool(1) { 49 | @Override 50 | public Object acquire() { 51 | return origin.acquire(); 52 | } 53 | 54 | @Override 55 | public boolean release(Object element) { 56 | boolean b = origin.release(element); 57 | Iterator> iterator = listeners.iterator(); 58 | while (iterator.hasNext()) { 59 | WeakReference reference = iterator.next(); 60 | CanvasRecycleListener recycleListener = reference.get(); 61 | if (recycleListener == null) { 62 | iterator.remove(); 63 | } else { 64 | recycleListener.onRecycle((Canvas) element); 65 | } 66 | } 67 | return b; 68 | } 69 | }; 70 | 71 | try { 72 | field.set(null, pool); 73 | } catch (IllegalAccessException e) { 74 | throw new RuntimeException(e); 75 | } 76 | } 77 | 78 | public void registerListener(CanvasRecycleListener listener) { 79 | listeners.add(new WeakReference<>(listener)); 80 | } 81 | 82 | public void removeListener(CanvasRecycleListener listener) { 83 | Iterator> iterator = listeners.iterator(); 84 | while (iterator.hasNext()) { 85 | WeakReference reference = iterator.next(); 86 | CanvasRecycleListener recycleListener = reference.get(); 87 | if (recycleListener == null || recycleListener == listener) { 88 | iterator.remove(); 89 | } 90 | } 91 | } 92 | 93 | 94 | } 95 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/canvaspool/CanvasRecycleListener.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.canvaspool; 2 | 3 | import android.graphics.Canvas; 4 | 5 | public interface CanvasRecycleListener { 6 | void onRecycle(Canvas canvas); 7 | } -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/canvaspool/MySynchronizedPool.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.canvaspool; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | import android.util.Pools; 6 | import android.view.DisplayListCanvas; 7 | import android.view.RenderNode; 8 | import android.view.Surface; 9 | import android.view.View; 10 | import android.view.ViewRootImpl; 11 | 12 | import java.lang.reflect.Field; 13 | 14 | public class MySynchronizedPool extends Pools.SynchronizedPool { 15 | private Pools.SynchronizedPool origin; 16 | 17 | public MySynchronizedPool(Pools.SynchronizedPool origin) { 18 | super(1, null); 19 | this.origin = origin; 20 | } 21 | 22 | @Override 23 | public Object acquire() { 24 | Object o = origin.acquire(); 25 | System.out.println("MySynchronizedPool...acquire:" + o); 26 | return o; 27 | } 28 | 29 | @Override 30 | public boolean release(Object element) { 31 | System.out.println("MySynchronizedPool...release:" + element);//DisplayListCanvas 32 | 33 | 34 | // Canvas canvas = (Canvas) element; 35 | // int w = canvas.getWidth(); 36 | // int h = canvas.getHeight(); 37 | 38 | // canvas.clipRect(0,0,w*2,h*2, Region.Op.REPLACE); 39 | // canvas.drawColor(0x6600ff00); 40 | // System.out.println("w:h " + w + " " + h); 41 | 42 | 43 | 44 | // 45 | /* 46 | private RenderNode(String name, View owningView) { 47 | 147 mNativeRenderNode = nCreate(name); 48 | 148 NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode); 49 | 149 mOwningView = owningView; 50 | 150 } 51 | 151 52 | */ 53 | 54 | ((Canvas) element).drawColor(0x88FF0000); 55 | 56 | try { 57 | Field mWidthF = DisplayListCanvas.class.getDeclaredField("mWidth"); 58 | mWidthF.setAccessible(true); 59 | int mWidth = (int) mWidthF.get(element); 60 | 61 | Field mHeightF = DisplayListCanvas.class.getDeclaredField("mHeight"); 62 | mHeightF.setAccessible(true); 63 | int mHeight = (int) mHeightF.get(element); 64 | 65 | 66 | Field field = DisplayListCanvas.class.getDeclaredField("mNode"); 67 | field.setAccessible(true); 68 | RenderNode renderNode = (RenderNode) field.get(element); 69 | if (renderNode == null) { 70 | System.out.println(element + ":" + renderNode + ":" + mWidth + ":" + mHeight); 71 | } else { 72 | Field mOwningViewField = RenderNode.class.getDeclaredField("mOwningView"); 73 | mOwningViewField.setAccessible(true); 74 | View view = (View) mOwningViewField.get(renderNode); 75 | System.out.println(element + ":" + renderNode + ":" + mWidth + ":" + mHeight + ":" + view); 76 | } 77 | 78 | } catch (Exception e) { 79 | throw new RuntimeException(e); 80 | } 81 | 82 | return origin.release(element); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/input/InputEventCompatProcessorV30.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.input; 2 | 3 | import android.content.Context; 4 | import android.view.InputEvent; 5 | import android.view.InputEventCompatProcessor; 6 | import android.view.ViewRootImpl; 7 | 8 | import java.lang.reflect.Field; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.List; 12 | 13 | public class InputEventCompatProcessorV30 extends InputEventCompatProcessor { 14 | private InputEventCompatProcessor originInputEventCompatProcessor; 15 | private InputEventListener listener; 16 | 17 | public InputEventCompatProcessorV30(Context context, ViewRootImpl viewRootImpl, InputEventListener listener) { 18 | super(context); 19 | this.listener = listener; 20 | try { 21 | Field field = viewRootImpl.getClass().getDeclaredField("mInputCompatProcessor"); 22 | field.setAccessible(true); 23 | originInputEventCompatProcessor = (InputEventCompatProcessor) field.get(viewRootImpl); 24 | field.set(viewRootImpl, this); 25 | } catch (Exception e) { 26 | throw new RuntimeException(e); 27 | } 28 | } 29 | 30 | @Override 31 | public InputEvent processInputEventBeforeFinish(InputEvent e) { 32 | return originInputEventCompatProcessor.processInputEventBeforeFinish(e); 33 | } 34 | 35 | @Override 36 | public List processInputEventForCompatibility(InputEvent e) { 37 | List list; 38 | if (listener.onBeforeInputEvent(e)) { 39 | list = new ArrayList<>(); 40 | } else { 41 | list = originInputEventCompatProcessor.processInputEventForCompatibility(e); 42 | } 43 | listener.onAfterInputEvent(e); 44 | return list; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/input/InputEventListener.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.input; 2 | 3 | import android.view.InputEvent; 4 | 5 | public interface InputEventListener { 6 | 7 | boolean onBeforeInputEvent(InputEvent inputEvent); 8 | 9 | void onAfterInputEvent(InputEvent inputEvent); 10 | } 11 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/input/InputEventProcessorCompact.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.input; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.os.Looper; 6 | import android.util.SparseIntArray; 7 | import android.view.InputChannel; 8 | import android.view.InputEventReceiver; 9 | import android.view.ViewRootImpl; 10 | 11 | import com.wanjian.sak.unsafe.UnsafeProxy; 12 | 13 | import java.lang.reflect.Field; 14 | 15 | public abstract class InputEventProcessorCompact { 16 | public static void get(Context context, ViewRootImpl viewRootImpl, InputEventListener listener) { 17 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 18 | new InputEventCompatProcessorV30(context, viewRootImpl, listener); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/input/InputEventReceiverCompact.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.input; 2 | 3 | import android.os.Build; 4 | import android.os.Looper; 5 | import android.util.SparseIntArray; 6 | import android.view.InputChannel; 7 | import android.view.InputEventReceiver; 8 | import android.view.View; 9 | import android.view.ViewRootImpl; 10 | 11 | import com.wanjian.sak.unsafe.UnsafeProxy; 12 | 13 | import java.lang.reflect.Field; 14 | 15 | public abstract class InputEventReceiverCompact { 16 | 17 | public static void get(ViewRootImpl viewRootImpl, InputEventListener listener) { 18 | InputChannel inputChannel = getInputChannel(viewRootImpl); 19 | Looper looper = Looper.getMainLooper();//todo 20 | InputEventReceiver originInputEventReceiver = getOriginInputEventReceiver(viewRootImpl); 21 | InputEventReceiver inputEventReceiver; 22 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 23 | inputEventReceiver = new InputEventReceiverV29Impl(inputChannel, looper, viewRootImpl, listener, originInputEventReceiver); 24 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { 25 | inputEventReceiver = new InputEventReceiverV27Impl(inputChannel, looper, viewRootImpl, listener, originInputEventReceiver); 26 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 27 | inputEventReceiver = new InputEventReceiverV21Impl(inputChannel, looper, viewRootImpl, listener, originInputEventReceiver); 28 | } else { 29 | throw new RuntimeException("unsuooprt"); 30 | } 31 | replace(viewRootImpl, originInputEventReceiver, inputEventReceiver); 32 | } 33 | 34 | private static InputEventReceiver getOriginInputEventReceiver(ViewRootImpl viewRootImpl) { 35 | try { 36 | Field mInputEventReceiverF = ViewRootImpl.class.getDeclaredField("mInputEventReceiver"); 37 | mInputEventReceiverF.setAccessible(true); 38 | return (InputEventReceiver) mInputEventReceiverF.get(viewRootImpl); 39 | } catch (Exception e) { 40 | throw new RuntimeException(e); 41 | } 42 | } 43 | 44 | 45 | private static InputChannel getInputChannel(ViewRootImpl viewRoot) { 46 | try { 47 | Field mInputChannelF = ViewRootImpl.class.getDeclaredField("mInputChannel"); 48 | mInputChannelF.setAccessible(true); 49 | return (InputChannel) mInputChannelF.get(viewRoot); 50 | } catch (Exception e) { 51 | throw new RuntimeException(e); 52 | } 53 | } 54 | 55 | private static void replace(ViewRootImpl viewRootImpl, InputEventReceiver originInputEventReceiver, InputEventReceiver myInputEventReceiver) { 56 | try { 57 | Field mInputEventReceiverF = ViewRootImpl.class.getDeclaredField("mInputEventReceiver"); 58 | Field mSeqMapField = InputEventReceiver.class.getDeclaredField("mSeqMap"); 59 | mSeqMapField.setAccessible(true); 60 | SparseIntArray originmSeqMap = (SparseIntArray) mSeqMapField.get(originInputEventReceiver); 61 | 62 | //// 63 | mSeqMapField.set(myInputEventReceiver, originmSeqMap); // TODO: 2020/6/26 必须? 64 | 65 | long offset = UnsafeProxy.objectFieldOffset(mInputEventReceiverF); 66 | UnsafeProxy.putObject(viewRootImpl, offset, myInputEventReceiver); 67 | } catch (Exception e) { 68 | throw new RuntimeException(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/input/InputEventReceiverHolder.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.input; 2 | 3 | public class InputEventReceiverHolder { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/rendernode/RenderNodeCompact.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.rendernode; 2 | 3 | import android.graphics.Canvas; 4 | import android.os.Build; 5 | 6 | public abstract class RenderNodeCompact { 7 | RenderNodeCompact() { 8 | 9 | } 10 | 11 | public static RenderNodeCompact create(String name) { 12 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 13 | return new RenderNodeV29Impl(name); 14 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 15 | return new RenderNodeV23Impl(name); 16 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 17 | return new RenderNodeV21Impl(name); 18 | } else { 19 | throw new RuntimeException("unsupport android version"); 20 | } 21 | } 22 | 23 | public abstract void drawRenderNode(Canvas canvas); 24 | 25 | public abstract Canvas beginRecording(int width, int height); 26 | 27 | public abstract void endRecording(Canvas canvas); 28 | 29 | public abstract boolean isValid(); 30 | } 31 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/rendernode/RenderNodeV21Impl.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.rendernode; 2 | 3 | import android.graphics.Canvas; 4 | import android.view.DisplayListCanvas; 5 | import android.view.HardwareCanvas; 6 | import android.view.RenderNode; 7 | 8 | import java.lang.reflect.Method; 9 | 10 | public class RenderNodeV21Impl extends RenderNodeCompact { 11 | 12 | private RenderNode renderNode; 13 | 14 | public RenderNodeV21Impl(String name) { 15 | renderNode = RenderNode.create(name, null); 16 | } 17 | 18 | @Override 19 | public void drawRenderNode(Canvas canvas) { 20 | ((HardwareCanvas) canvas).drawRenderNode(renderNode); 21 | } 22 | 23 | @Override 24 | public HardwareCanvas beginRecording(int width, int height) { 25 | renderNode.setLeftTopRightBottom(0, 0, width, height); 26 | try { 27 | Method method = RenderNode.class.getDeclaredMethod("start", int.class, int.class); 28 | method.setAccessible(true); 29 | return (HardwareCanvas) method.invoke(renderNode, width, height); 30 | } catch (Exception e) { 31 | throw new RuntimeException(e); 32 | } 33 | } 34 | 35 | @Override 36 | public void endRecording(Canvas canvas) { 37 | renderNode.end((HardwareCanvas) canvas); 38 | } 39 | 40 | @Override 41 | public boolean isValid() { 42 | return renderNode.isValid(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/rendernode/RenderNodeV23Impl.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.rendernode; 2 | 3 | import android.graphics.Canvas; 4 | import android.view.DisplayListCanvas; 5 | import android.view.HardwareCanvas; 6 | import android.view.RenderNode; 7 | import android.view.ThreadedRenderer; 8 | 9 | import java.lang.reflect.Method; 10 | 11 | public class RenderNodeV23Impl extends RenderNodeCompact { 12 | 13 | private RenderNode renderNode; 14 | 15 | public RenderNodeV23Impl(String name) { 16 | renderNode = RenderNode.create(name, null); 17 | } 18 | 19 | @Override 20 | public void drawRenderNode(Canvas canvas) { 21 | ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 22 | } 23 | 24 | 25 | @Override 26 | public DisplayListCanvas beginRecording(int width, int height) { 27 | renderNode.setLeftTopRightBottom(0, 0, width, height); 28 | return renderNode.start(width,height); 29 | } 30 | 31 | @Override 32 | public void endRecording(Canvas canvas) { 33 | renderNode.end((DisplayListCanvas) canvas); 34 | } 35 | 36 | @Override 37 | public boolean isValid() { 38 | return renderNode.isValid(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/rendernode/RenderNodeV29Impl.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.rendernode; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.RecordingCanvas; 5 | import android.graphics.RenderNode; 6 | 7 | import java.lang.reflect.Method; 8 | 9 | public class RenderNodeV29Impl extends RenderNodeCompact { 10 | 11 | private RenderNode renderNode; 12 | 13 | public RenderNodeV29Impl(String name) { 14 | renderNode = new RenderNode(name); 15 | } 16 | 17 | @Override 18 | public void drawRenderNode(Canvas canvas) { 19 | ((RecordingCanvas) canvas).drawRenderNode(renderNode); 20 | } 21 | 22 | @Override 23 | public RecordingCanvas beginRecording(int width, int height) { 24 | // renderNode.setLeftTopRightBottom(0, 0, width, height); 25 | try { 26 | Method method = RenderNode.class.getDeclaredMethod("setLeftTopRightBottom", int.class, int.class, int.class, int.class); 27 | method.setAccessible(true); 28 | method.invoke(renderNode, 0, 0, width, height); 29 | } catch (Exception e) { 30 | throw new RuntimeException(e); 31 | } 32 | return renderNode.beginRecording(); 33 | } 34 | 35 | @Override 36 | public void endRecording(Canvas canvas) { 37 | renderNode.endRecording(); 38 | } 39 | 40 | @Override 41 | public boolean isValid() { 42 | return renderNode.hasDisplayList(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/traversals/MyTraversalRunnable.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.traversals; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | import android.view.ViewRootImpl; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class MyTraversalRunnable implements Runnable { 11 | private ViewRootImpl $$viewRootImpl; 12 | private Runnable originTraversals; 13 | private View rootView; 14 | private List listeners = new ArrayList<>(); 15 | 16 | public MyTraversalRunnable(Runnable originTraversals, View rootView) { 17 | $$viewRootImpl = (ViewRootImpl) rootView.getRootView().getParent(); 18 | this.originTraversals = originTraversals; 19 | this.rootView = rootView; 20 | } 21 | 22 | @Override 23 | public void run() { 24 | Log.d("TAG", "run: "+$$viewRootImpl); 25 | notifyBeforeRun(); 26 | originTraversals.run(); 27 | notifyAfterRun(); 28 | } 29 | 30 | private void notifyBeforeRun() { 31 | for (ViewTraversalsListener listener : listeners) { 32 | listener.onBeforeTraversal(rootView); 33 | } 34 | } 35 | 36 | private void notifyAfterRun() { 37 | for (ViewTraversalsListener listener : listeners) { 38 | listener.onAfterTraversal(rootView); 39 | } 40 | } 41 | 42 | 43 | public void addTraversalsListener(ViewTraversalsListener listener) { 44 | listeners.add(listener); 45 | } 46 | 47 | public void removeTraversalsListener(ViewTraversalsListener listener) { 48 | listeners.remove(listener); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/traversals/ViewTraversalsCompact.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.traversals; 2 | 3 | import android.view.View; 4 | import android.view.ViewRootImpl; 5 | 6 | import com.wanjian.sak.unsafe.UnsafeProxy; 7 | 8 | import java.lang.reflect.Field; 9 | 10 | public class ViewTraversalsCompact { 11 | static Field sTraversalRunnableF; 12 | 13 | static { 14 | try { 15 | sTraversalRunnableF = ViewRootImpl.class.getDeclaredField("mTraversalRunnable"); 16 | sTraversalRunnableF.setAccessible(true); 17 | } catch (Exception e) { 18 | throw new RuntimeException(e); 19 | } 20 | } 21 | 22 | public void register(ViewRootImpl viewRootImpl, View view, ViewTraversalsListener listener) { 23 | 24 | Runnable originTraversal = null; 25 | try { 26 | originTraversal = (Runnable) sTraversalRunnableF.get(viewRootImpl); 27 | } catch (IllegalAccessException e) { 28 | throw new RuntimeException(e); 29 | } 30 | 31 | if (originTraversal instanceof MyTraversalRunnable) { 32 | ((MyTraversalRunnable) originTraversal).addTraversalsListener(listener); 33 | return; 34 | } 35 | 36 | MyTraversalRunnable myTraversal = new MyTraversalRunnable(originTraversal, view); 37 | 38 | myTraversal.addTraversalsListener(listener); 39 | 40 | long offset = UnsafeProxy.objectFieldOffset(sTraversalRunnableF); 41 | 42 | UnsafeProxy.putObject(viewRootImpl, offset, myTraversal); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/traversals/ViewTraversalsListener.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.traversals; 2 | 3 | import android.view.View; 4 | 5 | public interface ViewTraversalsListener { 6 | 7 | void onBeforeTraversal(View rootView); 8 | 9 | void onAfterTraversal(View rootView); 10 | } 11 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/window/compact/IWindowChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.window.compact; 2 | 3 | import android.view.View; 4 | import android.view.ViewRootImpl; 5 | 6 | public interface IWindowChangeListener { 7 | void onAddWindow(ViewRootImpl viewRootImpl, View rootView); 8 | 9 | void onRemoveWindow(ViewRootImpl viewRootImpl, View rootView); 10 | } 11 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/window/compact/WindowRootViewCompactV18Impl.java: -------------------------------------------------------------------------------- 1 | //package com.wanjian.sak.system.window.compact; 2 | // 3 | // 4 | //import android.support.annotation.NonNull; 5 | //import android.view.View; 6 | //import android.view.ViewRootImpl; 7 | // 8 | //import java.lang.reflect.Field; 9 | //import java.lang.reflect.InvocationTargetException; 10 | //import java.lang.reflect.Method; 11 | //import java.util.ArrayList; 12 | //import java.util.List; 13 | // 14 | //class WindowRootViewCompactV18Impl extends WindowRootViewCompactV16Impl { 15 | // 16 | // private Field mViewsField; 17 | // private Object mWindowManagerGlobal; 18 | // private List changeListeners = new ArrayList<>(); 19 | // private ViewRootImpl[] lastViews; 20 | // 21 | // WindowRootViewCompactV18Impl() { 22 | // super(null); 23 | // } 24 | // 25 | // @Override 26 | // void init() { 27 | // try { 28 | // Class wmClz = Class.forName("android.view.WindowManagerGlobal"); 29 | // Method getInstanceMethod = wmClz.getDeclaredMethod("getInstance"); 30 | // mWindowManagerGlobal = getInstanceMethod.invoke(wmClz); 31 | // mViewsField = wmClz.getDeclaredField("mRoots"); 32 | // mViewsField.setAccessible(true); 33 | // lastViews = (ViewRootImpl[]) mViewsField.get(mWindowManagerGlobal); 34 | // } catch (ClassNotFoundException e) { 35 | // throw new RuntimeException(e); 36 | // } catch (NoSuchMethodException e) { 37 | // throw new RuntimeException(e); 38 | // } catch (IllegalAccessException e) { 39 | // throw new RuntimeException(e); 40 | // } catch (InvocationTargetException e) { 41 | // throw new RuntimeException(e); 42 | // } catch (NoSuchFieldException e) { 43 | // throw new RuntimeException(e); 44 | // } 45 | // } 46 | // 47 | // @Override 48 | // void check() { 49 | // if (changeListeners == null || changeListeners.isEmpty()) { 50 | // return; 51 | // } 52 | // try { 53 | // ViewRootImpl[] curViews = (ViewRootImpl[]) mViewsField.get(mWindowManagerGlobal); 54 | // if (curViews != lastViews) { 55 | // notifyWindowChange(lastViews, curViews, changeListeners); 56 | // lastViews = curViews; 57 | // } 58 | // } catch (IllegalAccessException e) { 59 | // throw new RuntimeException(e); 60 | // } 61 | // } 62 | // 63 | // @Override 64 | // void onAddWindowChangeListener(@NonNull IWindowChangeListener changeListener) { 65 | // changeListeners.add(changeListener); 66 | // if (lastViews == null) { 67 | // return; 68 | // } 69 | // for (ViewRootImpl view : lastViews) { 70 | // changeListener.onAddWindow(view); 71 | // } 72 | // } 73 | // 74 | // @Override 75 | // void onRemoveWindowChangeListener(@NonNull IWindowChangeListener changeListener) { 76 | // changeListeners.remove(changeListener); 77 | // } 78 | // 79 | //} -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/window/compact/WindowRootViewCompactV19Impl.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.window.compact; 2 | 3 | import android.view.View; 4 | import android.view.ViewRootImpl; 5 | 6 | import com.wanjian.sak.proxy.ProxyArrayList; 7 | 8 | import java.lang.reflect.Array; 9 | import java.lang.reflect.Field; 10 | import java.lang.reflect.InvocationTargetException; 11 | import java.lang.reflect.Method; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | class WindowRootViewCompactV19Impl extends WindowRootViewCompat { 16 | 17 | private List changeListeners = new ArrayList<>(); 18 | private List viewRoots; 19 | private List rootViews; 20 | 21 | WindowRootViewCompactV19Impl() { 22 | try { 23 | Class wmClz = Class.forName("android.view.WindowManagerGlobal"); 24 | Method getInstanceMethod = wmClz.getDeclaredMethod("getInstance"); 25 | Object managerGlobal = getInstanceMethod.invoke(wmClz); 26 | 27 | Field mViewsField = wmClz.getDeclaredField("mViews"); 28 | mViewsField.setAccessible(true); 29 | rootViews = (List) mViewsField.get(managerGlobal); 30 | mViewsField.set(managerGlobal, rootViews); 31 | mViewsField.setAccessible(false); 32 | 33 | Field mRootsField = wmClz.getDeclaredField("mRoots"); 34 | mRootsField.setAccessible(true); 35 | viewRoots = getProxy((ArrayList) mRootsField.get(managerGlobal)); 36 | mRootsField.set(managerGlobal, viewRoots); 37 | mRootsField.setAccessible(false); 38 | 39 | } catch (ClassNotFoundException e) { 40 | throw new RuntimeException(e); 41 | } catch (NoSuchMethodException e) { 42 | throw new RuntimeException(e); 43 | } catch (IllegalAccessException e) { 44 | throw new RuntimeException(e); 45 | } catch (InvocationTargetException e) { 46 | throw new RuntimeException(e); 47 | } catch (NoSuchFieldException e) { 48 | throw new RuntimeException(e); 49 | } 50 | } 51 | 52 | private ArrayList getProxy(final ArrayList list) { 53 | return new ProxyArrayList(list) { 54 | @Override 55 | public boolean add(ViewRootImpl object) { 56 | boolean b = super.add(object); 57 | int index=indexOf(object); 58 | View view=rootViews.get(index); 59 | for (IWindowChangeListener listener : changeListeners) { 60 | listener.onAddWindow(object,view); 61 | } 62 | return b; 63 | } 64 | 65 | @Override 66 | public ViewRootImpl remove(int index) { 67 | ViewRootImpl viewRoot = super.remove(index); 68 | View view=rootViews.get(index); 69 | for (IWindowChangeListener listener : changeListeners) { 70 | listener.onRemoveWindow(viewRoot,view); 71 | } 72 | return viewRoot; 73 | } 74 | 75 | @Override 76 | public boolean remove(Object object) { 77 | int index = indexOf(object); 78 | View view = rootViews.get(index); 79 | boolean b = super.remove(object); 80 | for (IWindowChangeListener listener : changeListeners) { 81 | listener.onRemoveWindow(((ViewRootImpl) object), view); 82 | } 83 | return b; 84 | } 85 | }; 86 | } 87 | 88 | @Override 89 | void onAddWindowChangeListener(IWindowChangeListener changeListener) { 90 | changeListeners.add(changeListener); 91 | for (int i = 0; i < viewRoots.size(); i++) { 92 | ViewRootImpl viewRoot=viewRoots.get(i); 93 | View view=rootViews.get(i); 94 | changeListener.onAddWindow(viewRoot,view); 95 | } 96 | 97 | } 98 | @Override 99 | void onRemoveWindowChangeListener(IWindowChangeListener changeListener) { 100 | changeListeners.remove(changeListener); 101 | } 102 | } -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/system/window/compact/WindowRootViewCompat.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.system.window.compact; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | 6 | /* 7 | * get the root view of all windows 8 | *

9 | * when you add view by windowManager.addView(), the root view may not be a DecorView 10 | *

11 | *

12 | * There are some differences when you want to get the root view 13 | *

14 | * 4.0.3_r1 WindowManagerImpl private View[] mViews; 15 | *

16 | * 4.0.4 WindowManagerImpl private View[] mViews; 17 | *

18 | * 4.1.1 WindowManagerImpl private View[] mViews; 19 | *

20 | * 4.1.2 WindowManagerImpl private View[] mViews; 21 | *

22 | * 4.2_r1 WindowManagerGlobal private View[] mViews 23 | *

24 | * 4.2.2 r1 WindowManagerGlobal private View[] mViews 25 | *

26 | * 4.3_r2.1 WindowManagerGlobal private View[] mViews; 27 | *

28 | * 4.4_r1 WindowManagerGlobal private final ArrayList<View> mViews 29 | *

30 | * 4.4.2_r1 WindowManagerGlobal private final ArrayList<View> mViews 31 | *

32 | * 5.0.0_r2 WindowManagerGlobal private final ArrayList<View> mViews 33 | *

34 | * 6.0.0_r1 WindowManagerGlobal private final ArrayList<View> mViews 35 | *

36 | * 7.0.0_r1 WindowManagerGlobal private final ArrayList<View> mViews 37 | *

38 | * 8.0.0_r4 WindowManagerGlobal private final ArrayList<View> mViews 39 | */ 40 | public abstract class WindowRootViewCompat { 41 | 42 | public static WindowRootViewCompat get(Context context) { 43 | WindowRootViewCompat windowRootViewCompat; 44 | 45 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 46 | windowRootViewCompat = new WindowRootViewCompactV19Impl(); 47 | } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1 48 | || Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR2) { 49 | throw new RuntimeException("unsupport"); 50 | // windowRootViewCompat = new WindowRootViewCompactV18Impl(); 51 | } else { 52 | throw new RuntimeException("unsupport"); 53 | // windowRootViewCompat = new WindowRootViewCompactV16Impl(context.getApplicationContext()); 54 | } 55 | return windowRootViewCompat; 56 | } 57 | 58 | public final void addWindowChangeListener(IWindowChangeListener changeListener) { 59 | if (changeListener == null) { 60 | return; 61 | } 62 | onAddWindowChangeListener(changeListener); 63 | } 64 | 65 | public final void removeWindowChangeListener(IWindowChangeListener changeListener) { 66 | if (changeListener == null) { 67 | return; 68 | } 69 | onRemoveWindowChangeListener(changeListener); 70 | } 71 | 72 | abstract void onAddWindowChangeListener(IWindowChangeListener changeListener); 73 | 74 | abstract void onRemoveWindowChangeListener(IWindowChangeListener changeListener); 75 | 76 | } 77 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/unsafe/ReflectUtils.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.unsafe; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | public class ReflectUtils { 6 | 7 | private static ReflectUtils sInstance; 8 | 9 | private ReflectUtils() { 10 | } 11 | 12 | public static ReflectUtils getInstance() { 13 | if (sInstance == null) { 14 | sInstance = new ReflectUtils(); 15 | } 16 | return sInstance; 17 | } 18 | 19 | public Method getMethod(Class clazz, String methodName, Class... values) { 20 | Method method = null; 21 | try { 22 | if (values != null) { 23 | method = clazz.getDeclaredMethod(methodName, values); 24 | } else { 25 | method = clazz.getDeclaredMethod(methodName); 26 | } 27 | } catch (NoSuchMethodException e) { 28 | e.printStackTrace(); 29 | } 30 | return method; 31 | } 32 | 33 | public Object invokeStaticMethod(Method method, Object... values) { 34 | return invokeMethod(method, null, values); 35 | } 36 | 37 | public Object invokeMethod(Method method, Object classValue, Object... values) { 38 | if (method != null) { 39 | try { 40 | return method.invoke(classValue, values); 41 | } catch (Exception e) { 42 | throw new RuntimeException(e); 43 | } 44 | } 45 | return null; 46 | } 47 | 48 | /** 49 | * 这里我们通过反射静态方法 getUnsafe()方法来获取Unsafe对象,其实在之前的代码 50 | * 的时候我们也可以直接反射静态的成员变量来直接获取Unsafe对象的,其实都是差不多的。 51 | */ 52 | public Object getUnsafe(Class clazz) { 53 | Method method = getMethod(clazz, "getUnsafe"); 54 | return invokeStaticMethod(method); 55 | } 56 | } -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/unsafe/UnsafeProxy.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.unsafe; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | 6 | public class UnsafeProxy { 7 | 8 | private static ReflectUtils sUtils; 9 | private static Class sUnsafeClass; 10 | private static Object sUnsafe; 11 | 12 | static { 13 | 14 | try { 15 | sUtils = ReflectUtils.getInstance(); 16 | sUnsafeClass = Class.forName("sun.misc.Unsafe"); 17 | sUnsafe = sUtils.getUnsafe(sUnsafeClass); 18 | } catch (ClassNotFoundException e) { 19 | e.printStackTrace(); 20 | } 21 | } 22 | 23 | 24 | public static long objectFieldOffset(Field field) { 25 | Method method = sUtils.getMethod(sUnsafeClass, "objectFieldOffset", Field.class); 26 | Object obj = sUtils.invokeMethod(method, sUnsafe, field); 27 | return obj == null ? 0 : (Long) obj; 28 | } 29 | 30 | 31 | public static long putObject(Object object, long offset, Object newValue) { 32 | Method method = sUtils.getMethod(sUnsafeClass, "putObject", Object.class, long.class, Object.class); 33 | Object obj = sUtils.invokeMethod(method, sUnsafe, object, offset, newValue); 34 | return obj == null ? 0 : (Long) obj; 35 | } 36 | } -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/utils/BitmapCreater.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.utils; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | /** 6 | * Created by wanjian on 2017/4/1. 7 | */ 8 | 9 | public class BitmapCreater { 10 | public static Bitmap create(int w, int h, Bitmap.Config config) { 11 | 12 | Check.isNull(config, "config"); 13 | if (w <= 0) { 14 | new IllegalArgumentException("w can not be <= 0").printStackTrace(); 15 | return null; 16 | } 17 | if (h <= 0) { 18 | new IllegalArgumentException("h can not be <= 0").printStackTrace(); 19 | return null; 20 | } 21 | for (int i = 0; i < 3; i++) { 22 | try { 23 | return Bitmap.createBitmap(w, h, config); 24 | } catch (Throwable e) { 25 | Runtime.getRuntime().gc(); 26 | } 27 | } 28 | return null; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/utils/Check.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.utils; 2 | 3 | /** 4 | * Created by wanjian on 2017/2/20. 5 | */ 6 | 7 | public class Check { 8 | 9 | public static void isNull(Object obj, String what) { 10 | if (obj == null) { 11 | throw new NullPointerException(what + " cannot be null !"); 12 | } 13 | } 14 | 15 | public static void throwException(String msg) { 16 | throw new RuntimeException(msg); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/utils/LoopQueue.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.utils; 2 | 3 | import java.util.LinkedList; 4 | 5 | public class LoopQueue { 6 | private int size; 7 | private LinkedList queue; 8 | private int cursor; 9 | 10 | public LoopQueue(int size) { 11 | if (size < 1) { 12 | throw new IllegalArgumentException(); 13 | } 14 | this.size = size; 15 | queue = new LinkedList(); 16 | } 17 | 18 | public T take() { 19 | if (has() == false) { 20 | throw new IllegalStateException("end!"); 21 | } 22 | return queue.get(cursor++); 23 | } 24 | 25 | public void append(T t) { 26 | if (queue.size() == size) { 27 | queue.remove(0); 28 | cursor--; 29 | if (cursor < 0) { 30 | cursor = 0; 31 | } 32 | } 33 | queue.add(t); 34 | } 35 | 36 | public boolean has() { 37 | return cursor != queue.size(); 38 | } 39 | 40 | public int maxSize() { 41 | return size; 42 | } 43 | 44 | public int size() { 45 | return queue.size(); 46 | } 47 | 48 | public void reset() { 49 | cursor = 0; 50 | } 51 | 52 | public void clean() { 53 | cursor = 0; 54 | queue.clear(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/utils/RunningActivityFetcher.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.utils; 2 | 3 | import android.app.Activity; 4 | 5 | import java.lang.ref.WeakReference; 6 | import java.lang.reflect.Field; 7 | import java.lang.reflect.Method; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | public class RunningActivityFetcher { 13 | 14 | private static Map mActivities; //ActivityThread.mActivities 15 | private static Field activityField;//ActivityClientRecord.activity 16 | 17 | public static List> fetch() { 18 | 19 | if (mActivities == null) { 20 | getmActivities(); 21 | } 22 | List> references = new ArrayList<>(); 23 | 24 | for (Object actRecord : mActivities.values()) { 25 | if (activityField == null) { 26 | getActivityField(actRecord); 27 | } 28 | if (activityField == null) { 29 | return null; 30 | } 31 | 32 | try { 33 | Activity activity = (Activity) activityField.get(actRecord); 34 | references.add(new WeakReference<>(activity)); 35 | } catch (Throwable throwable) { 36 | throwable.printStackTrace(); 37 | return null; 38 | } 39 | } 40 | return references; 41 | } 42 | 43 | private static void getActivityField(Object actRecord) { 44 | try { 45 | activityField = actRecord.getClass().getDeclaredField("activity"); 46 | activityField.setAccessible(true); 47 | } catch (Throwable throwable) { 48 | throwable.printStackTrace(); 49 | } 50 | } 51 | 52 | private static void getmActivities() { 53 | try { 54 | Class activityThreadClz = Class.forName("android.app.ActivityThread"); 55 | Method currentActivityThreadMethod = activityThreadClz.getDeclaredMethod("currentActivityThread"); 56 | currentActivityThreadMethod.setAccessible(true); 57 | Object activityThread = currentActivityThreadMethod.invoke(null); 58 | Field mActivitiesField = activityThreadClz.getDeclaredField("mActivities"); 59 | mActivitiesField.setAccessible(true); 60 | // 61 | mActivities = (Map) mActivitiesField.get(activityThread); 62 | } catch (Throwable throwable) { 63 | throwable.printStackTrace(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/utils/ScreenUtils.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.utils; 2 | 3 | import android.content.Context; 4 | 5 | public class ScreenUtils { 6 | 7 | public static int dp2px(Context context, int dip) { 8 | float density = context.getResources().getDisplayMetrics().density; 9 | return (int) (dip * density + 0.5); 10 | } 11 | 12 | public static int px2dp(Context context, float pxValue) { 13 | final float scale = context.getResources().getDisplayMetrics().density; 14 | return (int) (pxValue / scale + 0.5f); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/utils/SpanStrBuilder.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.utils; 2 | 3 | import android.text.SpannableString; 4 | import android.text.Spanned; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | 10 | public class SpanStrBuilder { 11 | 12 | private List charSequences = new ArrayList<>(); 13 | private List styles = new ArrayList<>(); 14 | 15 | 16 | public SpanStrBuilder append(Object charSequence, Object... style) { 17 | charSequences.add(charSequence); 18 | styles.add(style); 19 | return this; 20 | } 21 | 22 | 23 | public SpanStrBuilder append(Object charSequence) { 24 | charSequences.add(charSequence); 25 | styles.add(null); 26 | return this; 27 | } 28 | 29 | public SpannableString build() { 30 | StringBuilder builder = new StringBuilder(); 31 | for (Object chs : charSequences) { 32 | builder.append(chs); 33 | } 34 | 35 | SpannableString string = new SpannableString(builder); 36 | 37 | int start = 0; 38 | for (int i = 0; i < charSequences.size(); i++) { 39 | 40 | int len = String.valueOf(charSequences.get(i)).length(); 41 | Object[] o = styles.get(i); 42 | if (o != null) { 43 | for (Object o1 : o) { 44 | string.setSpan(o1, start, start + len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 45 | } 46 | } 47 | 48 | start += len; 49 | } 50 | return string; 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.utils; 2 | 3 | import android.app.Activity; 4 | import android.view.View; 5 | import android.view.ViewRootImpl; 6 | import android.widget.FrameLayout; 7 | import android.widget.RelativeLayout; 8 | import android.widget.ScrollView; 9 | 10 | import java.lang.ref.WeakReference; 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class Utils { 16 | public static ViewRootImpl[] diff(ViewRootImpl[] views1, ViewRootImpl[] views2) { 17 | List list1 = views1 == null ? new ArrayList() : Arrays.asList(views1); 18 | List list2 = views2 == null ? new ArrayList() : Arrays.asList(views2); 19 | List result = new ArrayList<>(32); 20 | 21 | for (ViewRootImpl view : list1) { 22 | if (list2.contains(view) == false) { 23 | result.add(view); 24 | } 25 | } 26 | ViewRootImpl[] array = new ViewRootImpl[result.size()]; 27 | result.toArray(array); 28 | return array; 29 | } 30 | 31 | public static Activity findAct(View view) { 32 | List> references = RunningActivityFetcher.fetch(); 33 | if (references == null) { 34 | return null; 35 | } 36 | for (WeakReference act : references) { 37 | Activity activity = act.get(); 38 | if (activity == null) { 39 | continue; 40 | } 41 | if (view == activity.getWindow().getDecorView().getRootView()) { 42 | return activity; 43 | } 44 | } 45 | return null; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/view/GridScroller.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.GridView; 6 | 7 | /** 8 | * 不会复用控件 9 | */ 10 | public class GridScroller extends GridView { 11 | public GridScroller(Context context) { 12 | super(context); 13 | } 14 | 15 | public GridScroller(Context context, AttributeSet attrs) { 16 | super(context, attrs); 17 | } 18 | 19 | @Override 20 | public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 21 | int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); 22 | super.onMeasure(widthMeasureSpec, expandSpec); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /saklib/src/main/java/com/wanjian/sak/view/SAKContainerView.java: -------------------------------------------------------------------------------- 1 | package com.wanjian.sak.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.FrameLayout; 6 | 7 | public class SAKContainerView extends FrameLayout { 8 | public SAKContainerView(Context context) { 9 | super(context); 10 | } 11 | 12 | public SAKContainerView(Context context, AttributeSet attrs) { 13 | super(context, attrs); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /saklib/src/main/res/animator/sak_shake_animator.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 22 | -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_background_color_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_background_color_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_border_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_border_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_checkbox_circle_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_checkbox_circle_checked.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_checkbox_circle_unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_checkbox_circle_unchecked.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_color_picker_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_color_picker_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_controller_type_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_controller_type_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_corner_measure_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_corner_measure_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_custom_info_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_custom_info_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_drag_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_drag_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_edit_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_edit_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_entrance_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_entrance_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_grid_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_grid_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_hori_measure_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_hori_measure_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_icon_scale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_icon_scale.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_img_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_img_size.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_launcher_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_layer_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_layer_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_layout_tree_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_layout_tree_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_margin_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_margin_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_padding_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_padding_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_page_name_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_page_name_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_performance_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_performance_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_pick_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_pick_view.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_relative_distance_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_relative_distance_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_shake_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_shake_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_text_color_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_text_color_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_text_size_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_text_size_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_ver_measure_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_ver_measure_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable-xxhdpi/sak_width_height_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable-xxhdpi/sak_width_height_icon.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_box_bag.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_card_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_circle_check_box_bag.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_corner_but_bag.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_edittext_focused.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_edittext_normal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_function_item_bag.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_icon_arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/saklib/src/main/res/drawable/sak_icon_arrow_down.png -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_input_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_radiogroup_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /saklib/src/main/res/drawable/sak_toast_bag.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /saklib/src/main/res/layout/sak_function_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 20 | 21 | 30 | 31 | 32 | 41 | -------------------------------------------------------------------------------- /saklib/src/main/res/layout/sak_performance_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 18 | 19 | 27 | 28 | 29 | 37 | 38 | 39 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /saklib/src/main/res/layout/sak_radiobutton.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /saklib/src/main/res/layout/sak_scalpel_opt_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /saklib/src/main/res/layout/sak_toast_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | -------------------------------------------------------------------------------- /saklib/src/main/res/layout/sak_view_info_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /saklib/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 边框 4 | 外边距 5 | 内边距 6 | 宽高 7 | 图片宽高 8 | 字体大小 9 | 字体颜色 10 | 强制图片宽高 11 | 自定义信息 12 | 水平直尺 13 | 竖直直尺 14 | 圆角尺 15 | 取色器 16 | 布局树 17 | 实时刷新 18 | 层级区间 19 | 单位 20 | 背景色 21 | View渲染时间 22 | 页面渲染时间 23 | View类型 24 | 关闭 25 | 确定 26 | 帮助 27 | Activity名称 28 | Fragment名称 29 | 编辑控件 30 | 网格 31 | 相对距离 32 | 移动控件 33 | 裁剪绘制范围 34 | 性能 35 | Measure 36 | Layout 37 | Draw 38 | Touch 39 | Handler 40 | 控件拾取 41 | UI更新时闪烁 42 | 43 | -------------------------------------------------------------------------------- /saklib/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #efefef 4 | #FFFFFF 5 | #f1f1f1 6 | #FF0000 7 | #FF333333 8 | #ff48c09e 9 | #c2c2c2 10 | -------------------------------------------------------------------------------- /saklib/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 70dp 4 | 90dp 5 | 40dp 6 | -------------------------------------------------------------------------------- /saklib/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Border 4 | Margin 5 | Padding 6 | Width Height 7 | Image Size 8 | Text Size 9 | Text Color 10 | Force Image Size 11 | Personal Info 12 | Horizontal Measure 13 | Vertical Measure 14 | Corner Measure 15 | Take Color 16 | Layout Tree 17 | Refresh 18 | Layer Range 19 | Unit 20 | Background Color 21 | View Rendering Performance 22 | Page Rendering Performance 23 | View Class 24 | Close 25 | OK 26 | Help 27 | ActivityName 28 | FragmentName 29 | Edit View 30 | Grid 31 | Relative Distance 32 | Translation 33 | Clip Draw 34 | Performance 35 | Measure 36 | Layout 37 | Draw 38 | Touch 39 | Handler 40 | Pick View 41 | Flash When UI Update 42 | -------------------------------------------------------------------------------- /saklib/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':saklib' 2 | include ':systemlib' 3 | 4 | dependencyResolutionManagement { 5 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 6 | repositories { 7 | google() 8 | mavenCentral() 9 | maven { url 'https://jitpack.io' } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /systemlib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /systemlib/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | namespace('com.wanjian.sak.lib') 5 | compileSdkVersion 33 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 33 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | 22 | } 23 | 24 | dependencies { 25 | } 26 | -------------------------------------------------------------------------------- /systemlib/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-notes/SwissArmyKnife/6c7c52c0b66db6cbd0fd47d681a808a3e875a8db/systemlib/consumer-rules.pro -------------------------------------------------------------------------------- /systemlib/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /systemlib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /systemlib/src/main/java/android/graphics/FrameInfo.java: -------------------------------------------------------------------------------- 1 | package android.graphics; 2 | 3 | public final class FrameInfo { 4 | 5 | public void markDrawStart() { 6 | } 7 | 8 | 9 | } -------------------------------------------------------------------------------- /systemlib/src/main/java/android/graphics/HardwareRenderer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.graphics; 18 | 19 | 20 | public abstract class HardwareRenderer { 21 | protected RenderNode mRootNode; 22 | 23 | public int syncAndDrawFrame(FrameInfo frameInfo) { 24 | return 0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /systemlib/src/main/java/android/graphics/RecordingCanvas.java: -------------------------------------------------------------------------------- 1 | package android.graphics; 2 | 3 | import android.util.Pools; 4 | 5 | public class RecordingCanvas extends Canvas { 6 | private static final int POOL_LIMIT = 25; 7 | private static final Pools.SynchronizedPool sPool = 8 | new Pools.SynchronizedPool<>(POOL_LIMIT); 9 | 10 | 11 | public void enableZ() { 12 | } 13 | 14 | public void disableZ() { 15 | } 16 | 17 | public void drawRenderNode(RenderNode renderNode) { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /systemlib/src/main/java/android/graphics/RenderNode.java: -------------------------------------------------------------------------------- 1 | package android.graphics; 2 | 3 | public class RenderNode { 4 | public RenderNode(String name) { 5 | 6 | } 7 | 8 | public boolean setLeftTopRightBottom(int left, int top, int right, int bottom) { 9 | return false; 10 | } 11 | 12 | public boolean setAlpha(float alpha) { 13 | return false; 14 | } 15 | 16 | public boolean setHasOverlappingRendering(boolean hasOverlappingRendering) { 17 | return false; 18 | } 19 | 20 | public boolean setClipToBounds(boolean clipToBounds) { 21 | return false; 22 | } 23 | 24 | 25 | public RecordingCanvas beginRecording(int width, int height) { 26 | return null; 27 | } 28 | 29 | public RecordingCanvas beginRecording() { 30 | return null; 31 | } 32 | 33 | 34 | public void endRecording() { 35 | } 36 | 37 | public boolean hasDisplayList() { 38 | throw new IllegalStateException(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /systemlib/src/main/java/android/util/Pools.java: -------------------------------------------------------------------------------- 1 | package android.util; 2 | 3 | public final class Pools { 4 | 5 | /** 6 | * Interface for managing a pool of objects. 7 | * 8 | * @param The pooled type. 9 | */ 10 | public static interface Pool { 11 | 12 | /** 13 | * @return An instance from the pool if such, null otherwise. 14 | */ 15 | public T acquire(); 16 | 17 | /** 18 | * Release an instance to the pool. 19 | * 20 | * @param instance The instance to release. 21 | * @return Whether the instance was put in the pool. 22 | * @throws IllegalStateException If the instance is already in the pool. 23 | */ 24 | public boolean release(T instance); 25 | } 26 | 27 | private Pools() { 28 | /* do nothing - hiding constructor */ 29 | } 30 | 31 | /** 32 | * Simple (non-synchronized) pool of objects. 33 | * 34 | * @param The pooled type. 35 | */ 36 | public static class SimplePool implements Pool { 37 | private final Object[] mPool; 38 | 39 | private int mPoolSize; 40 | 41 | /** 42 | * Creates a new instance. 43 | * 44 | * @param maxPoolSize The max pool size. 45 | * @throws IllegalArgumentException If the max pool size is less than zero. 46 | */ 47 | public SimplePool(int maxPoolSize) { 48 | if (maxPoolSize <= 0) { 49 | throw new IllegalArgumentException("The max pool size must be > 0"); 50 | } 51 | mPool = new Object[maxPoolSize]; 52 | } 53 | 54 | @Override 55 | @SuppressWarnings("unchecked") 56 | public T acquire() { 57 | if (mPoolSize > 0) { 58 | final int lastPooledIndex = mPoolSize - 1; 59 | T instance = (T) mPool[lastPooledIndex]; 60 | mPool[lastPooledIndex] = null; 61 | mPoolSize--; 62 | return instance; 63 | } 64 | return null; 65 | } 66 | 67 | @Override 68 | public boolean release(T instance) { 69 | if (isInPool(instance)) { 70 | throw new IllegalStateException("Already in the pool!"); 71 | } 72 | if (mPoolSize < mPool.length) { 73 | mPool[mPoolSize] = instance; 74 | mPoolSize++; 75 | return true; 76 | } 77 | return false; 78 | } 79 | 80 | private boolean isInPool(T instance) { 81 | for (int i = 0; i < mPoolSize; i++) { 82 | if (mPool[i] == instance) { 83 | return true; 84 | } 85 | } 86 | return false; 87 | } 88 | } 89 | 90 | /** 91 | * Synchronized pool of objects. 92 | * 93 | * @param The pooled type. 94 | */ 95 | public static class SynchronizedPool extends SimplePool { 96 | private final Object mLock; 97 | 98 | /** 99 | * Creates a new instance. 100 | * 101 | * @param maxPoolSize The max pool size. 102 | * @param lock an optional custom object to synchronize on 103 | * @throws IllegalArgumentException If the max pool size is less than zero. 104 | */ 105 | public SynchronizedPool(int maxPoolSize, Object lock) { 106 | super(maxPoolSize); 107 | mLock = lock; 108 | } 109 | 110 | /** 111 | * @see #SynchronizedPool(int, Object) 112 | */ 113 | public SynchronizedPool(int maxPoolSize) { 114 | this(maxPoolSize, new Object()); 115 | } 116 | 117 | @Override 118 | public T acquire() { 119 | synchronized (mLock) { 120 | return super.acquire(); 121 | } 122 | } 123 | 124 | @Override 125 | public boolean release(T element) { 126 | synchronized (mLock) { 127 | return super.release(element); 128 | } 129 | } 130 | } 131 | } -------------------------------------------------------------------------------- /systemlib/src/main/java/android/view/DisplayListCanvas.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | import android.util.Pools; 6 | 7 | public class DisplayListCanvas extends Canvas { 8 | 9 | private static final int POOL_LIMIT = 25; 10 | //android 6.0,7.0,7.1,8.0,8.1,9.0 11 | private static final Pools.SynchronizedPool sPool = 12 | new Pools.SynchronizedPool(POOL_LIMIT); 13 | 14 | public void onPreDraw(Rect dirty) { 15 | } 16 | 17 | public void insertReorderBarrier() { 18 | } 19 | 20 | public void insertInorderBarrier() { 21 | } 22 | 23 | public void drawRenderNode(RenderNode renderNode) { 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /systemlib/src/main/java/android/view/GLES20RecordingCanvas.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | import android.util.Pools; 4 | 5 | class GLES20RecordingCanvas { 6 | // The recording canvas pool should be large enough to handle a deeply nested 7 | // view hierarchy because display lists are generated recursively. 8 | private static final int POOL_LIMIT = 25; 9 | //android 5.0,5.1 10 | private static final Pools.SynchronizedPool sPool = 11 | new Pools.SynchronizedPool(POOL_LIMIT); 12 | 13 | } -------------------------------------------------------------------------------- /systemlib/src/main/java/android/view/HardwareCanvas.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | import android.graphics.Canvas; 4 | 5 | //只有Android 5.0-5.1 才有HardwareCanvas,HardwareCanvas和DisplayListCanvas 6 | // 都是canvas的直接子类,为了编译通过指定HardwareCanvas extends DisplayListCanvas 7 | 8 | public class HardwareCanvas extends Canvas { 9 | 10 | public void insertReorderBarrier() { 11 | } 12 | 13 | public void insertInorderBarrier() { 14 | } 15 | 16 | public void drawRenderNode(RenderNode renderNode) { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /systemlib/src/main/java/android/view/HardwareLayer.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | public class HardwareLayer { 4 | boolean isEnabled() { 5 | return false; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /systemlib/src/main/java/android/view/InputChannel.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | public class InputChannel { 4 | } 5 | -------------------------------------------------------------------------------- /systemlib/src/main/java/android/view/InputEventCompatProcessor.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package android.view; 4 | 5 | import android.content.Context; 6 | import android.os.Build; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class InputEventCompatProcessor { 12 | 13 | 14 | public InputEventCompatProcessor(Context context) { 15 | 16 | } 17 | 18 | 19 | public List processInputEventForCompatibility(InputEvent e) { 20 | 21 | return null; 22 | } 23 | 24 | 25 | public InputEvent processInputEventBeforeFinish(InputEvent e) { 26 | // No changes needed 27 | return e; 28 | } 29 | } -------------------------------------------------------------------------------- /systemlib/src/main/java/android/view/InputEventReceiver.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | import android.os.Looper; 4 | 5 | public abstract class InputEventReceiver { 6 | 7 | public InputEventReceiver(InputChannel inputChannel, Looper looper) { 8 | 9 | } 10 | public void onInputEvent(InputEvent event, int displayId){} 11 | public void onInputEvent(InputEvent event) { 12 | 13 | } 14 | 15 | 16 | public void onBatchedInputEventPending() { 17 | 18 | } 19 | 20 | 21 | public void dispose() { 22 | 23 | } 24 | 25 | 26 | protected void finalize() throws Throwable { 27 | 28 | } 29 | 30 | 31 | public final void finishInputEvent(InputEvent event, boolean handled) { 32 | 33 | } 34 | 35 | // public final boolean consumeBatchedInputEvents(long frameTimeNanos) { 36 | // return false; 37 | // } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /systemlib/src/main/java/android/view/RenderNode.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | import android.graphics.Outline; 4 | 5 | public class RenderNode { 6 | public DisplayListCanvas start(int width, int height) { 7 | return null; 8 | } 9 | 10 | // public HardwareCanvas start(int width, int height,Object...obj) { 11 | // return null; 12 | // } 13 | 14 | private RenderNode() { 15 | } 16 | 17 | public static RenderNode create(String name, View owningView) { 18 | return null; 19 | } 20 | 21 | public void end(HardwareCanvas canvas) { 22 | } 23 | 24 | 25 | public void end(DisplayListCanvas canvas) { 26 | } 27 | 28 | public boolean setAlpha(float alpha) { 29 | return false; 30 | } 31 | 32 | 33 | public boolean setLeftTopRightBottom(int left, int top, int right, int bottom){ 34 | return false; 35 | } 36 | 37 | public boolean setOutline( Outline outline) { 38 | return false; 39 | } 40 | 41 | public boolean setHasOverlappingRendering(boolean hasOverlappingRendering) { 42 | return false; 43 | } 44 | 45 | public boolean setClipToBounds(boolean clipToBounds) { 46 | return false; 47 | } 48 | public boolean isValid() { 49 | return false; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /systemlib/src/main/java/android/view/ThreadedRenderer.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | public abstract class ThreadedRenderer extends HardwareRenderer { 4 | private int mInsetTop, mInsetLeft; 5 | public void notifyFramePending() {} 6 | } 7 | -------------------------------------------------------------------------------- /systemlib/src/main/java/android/view/ViewFrameInfo.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package android.view; 4 | 5 | import android.graphics.FrameInfo; 6 | 7 | 8 | public class ViewFrameInfo { 9 | public long drawStart; 10 | public long flags; 11 | 12 | private int mInputEventId; 13 | 14 | 15 | public void populateFrameInfo(FrameInfo frameInfo) { 16 | 17 | } 18 | 19 | public void reset() { 20 | 21 | } 22 | 23 | public void markDrawStart() { 24 | drawStart = System.nanoTime(); 25 | } 26 | 27 | 28 | public void setInputEvent(int eventId) { 29 | mInputEventId = eventId; 30 | } 31 | } --------------------------------------------------------------------------------