mirror of
				https://gitee.com/csharpui/CPF.git
				synced 2025-11-01 00:46:56 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			465 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			465 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using System.Runtime.InteropServices;
 | |
| using System.Text;
 | |
| 
 | |
| using Android.App;
 | |
| using Android.Content;
 | |
| using Android.Graphics;
 | |
| using Android.OS;
 | |
| using Android.Runtime;
 | |
| using Android.Views;
 | |
| using Android.Views.InputMethods;
 | |
| using Android.Widget;
 | |
| using CPF.Drawing;
 | |
| using CPF.Input;
 | |
| using CPF.OpenGL;
 | |
| using CPF.Platform;
 | |
| using Javax.Microedition.Khronos.Egl;
 | |
| using GLES20 = global::Android.Opengl.GLES20;
 | |
| 
 | |
| namespace CPF.Android
 | |
| {
 | |
|     internal class AndroidView : SurfaceView, ISurfaceView, ISurfaceHolderCallback
 | |
|     {
 | |
|         public AndroidView(Context activity, UIElement content, CpfView cpfView) : base(activity)
 | |
|         {
 | |
|             if (CPF.Platform.Application.GetDrawingFactory().UseGPU)
 | |
|             {
 | |
|                 eglContext = new EglContext(this);
 | |
|                 Holder.AddCallback(this);
 | |
|                 //SetLayerType(LayerType.Hardware, null);
 | |
|             }
 | |
|             CpfView = cpfView;
 | |
|             this.Holder.SetFormat(Format.Rgba8888);
 | |
|             //SetOnTouchListener(this);
 | |
|             //SetOnKeyListener(this);
 | |
|             //this.activity = activity as Activity;
 | |
|             //if (content != null)
 | |
|             //{
 | |
|             //    root = new InnerView(this);
 | |
|             //    root.Background = CPF.Drawing.Color.White;
 | |
|             //    root.Children.Add(content);
 | |
|             //    root.Visibility = CPF.Visibility.Visible;
 | |
|             //    root.CanActivate = true;
 | |
|             //    root.LayoutUpdated += Root_LayoutUpdated;
 | |
|             //    scale = root.LayoutScaling;
 | |
|             //}
 | |
|             //this.FocusableInTouchMode = true;
 | |
|             //softKeyboardListner = new SoftKeyboardListner(this);
 | |
|             //ViewTreeObserver.AddOnGlobalLayoutListener(softKeyboardListner);
 | |
|             generalView = new GeneralView(this, content);
 | |
|             cpfView.AddView(this);
 | |
|             generalView.Create();
 | |
|         }
 | |
|         EglContext eglContext;
 | |
|         GeneralView generalView;
 | |
|         public CpfView CpfView { get; }
 | |
| 
 | |
|         public GeneralView GeneralView { get { return generalView; } }
 | |
| 
 | |
| 
 | |
|         //internal Activity activity;
 | |
|         //CPF.Controls.View root;
 | |
|         //PixelSize oldSize;
 | |
|         public CPF.Controls.View Root
 | |
|         {
 | |
|             get { return generalView.Root; }
 | |
|         }
 | |
| 
 | |
|         protected override int[] OnCreateDrawableState(int extraSpace)
 | |
|         {
 | |
|             //Invalidate();
 | |
|             generalView.OnCreateDrawableState(extraSpace);
 | |
|             return base.OnCreateDrawableState(extraSpace);
 | |
|         }
 | |
| 
 | |
| 
 | |
|         //bool _invalidateQueued;
 | |
|         public override void Invalidate()
 | |
|         {
 | |
|             //if (_invalidateQueued)
 | |
|             //{
 | |
|             //    return;
 | |
|             //}
 | |
|             //_invalidateQueued = true;
 | |
|             //Threading.Dispatcher.MainThread.BeginInvoke(() =>
 | |
|             //{
 | |
|             //    _invalidateQueued = false;
 | |
|             //    if (CpfView.Handle != default)
 | |
|             //    {
 | |
|             //        OnPaint();
 | |
|             //    }
 | |
|             //});
 | |
|             generalView.Invalidate();
 | |
|         }
 | |
| 
 | |
|         public override void Invalidate(global::Android.Graphics.Rect dirty)
 | |
|         {
 | |
|             Invalidate();
 | |
|         }
 | |
| 
 | |
|         public override void Invalidate(int l, int t, int r, int b)
 | |
|         {
 | |
|             Invalidate();
 | |
|         }
 | |
| 
 | |
|         //float scale;
 | |
|         protected override void OnLayout(bool changed, int left, int top, int right, int bottom)
 | |
|         {
 | |
|             //base.OnLayout(changed, left, top, right, bottom);
 | |
|             //var size = new PixelSize(right, bottom);
 | |
|             //var sc = LayoutScaling;
 | |
|             //if (LayoutScaling != scale)
 | |
|             //{
 | |
|             //    scale = sc;
 | |
|             //    ScalingChanged();
 | |
|             //}
 | |
|             //if (size != oldSize)
 | |
|             //{
 | |
|             //    oldSize = size;
 | |
|             //    Resized(new Size(size.Width / LayoutScaling, size.Height / LayoutScaling));
 | |
|             //}
 | |
|             generalView.OnLayout(changed, left, top, right, bottom);
 | |
|         }
 | |
| 
 | |
|         PixelSize pixelSize;
 | |
|         public virtual void OnPaint()
 | |
|         {
 | |
|             //System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
 | |
|             //stopwatch.Start();
 | |
|             var root = generalView.Root;
 | |
|             if (eglContext != null)
 | |
|             {
 | |
|                 var _window = ANativeWindow_fromSurface(JNIEnv.Handle, Holder.Surface.Handle);
 | |
|                 if (_window == IntPtr.Zero)
 | |
|                     return;//获取window操作可以解决下拉框图像错位问题
 | |
|                 ANativeWindow_release(_window);
 | |
| 
 | |
|                 root.LayoutManager.ExecuteLayoutPass();
 | |
|                 if (eglContext.EglSurface != null)
 | |
|                 {
 | |
|                     eglContext.MakeCurrent();
 | |
|                     //var ir = generalView.invalidateRect * RenderScaling;
 | |
|                     //GLES20.GlViewport(ir.X,ir.Y,ir.Width,ir.Height);
 | |
|                     eglContext.GetFramebufferInfo(out var fb, out var sam, out var ste);
 | |
|                     using (DrawingContext dc = DrawingContext.FromRenderTarget(new OpenGlRenderTarget(eglContext, pixelSize.Width, pixelSize.Height, fb, sam, ste)))
 | |
|                     {
 | |
|                         if (root.LayoutManager.VisibleUIElements != null)
 | |
|                         {
 | |
|                             root.RenderView(dc, new Drawing.Rect(0, 0, pixelSize.Width, pixelSize.Height));
 | |
|                         }
 | |
|                     }
 | |
|                     eglContext.SwapBuffers();
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 var surface = this.Holder.Surface;
 | |
|                 var _window = ANativeWindow_fromSurface(JNIEnv.Handle, surface.Handle);
 | |
|                 if (_window == IntPtr.Zero)
 | |
|                     return;
 | |
|                 //throw new Exception("Unable to obtain ANativeWindow");
 | |
|                 ANativeWindow_Buffer buffer;
 | |
|                 var rc = new ARect()
 | |
|                 {
 | |
|                     right = ANativeWindow_getWidth(_window),
 | |
|                     bottom = ANativeWindow_getHeight(_window)
 | |
|                 };
 | |
|                 var size = new PixelSize(rc.right, rc.bottom);
 | |
|                 if (size.Width != Width || size.Height != Height)
 | |
|                 {//有时候渲染尺寸和控件尺寸不一样
 | |
|                  //surface.SetSize(size.Width, size.Height);
 | |
|                  //Holder.SetSizeFromLayout();
 | |
|                     Holder.SetFixedSize(size.Width, size.Height);
 | |
|                 }
 | |
|                 rc = new ARect()
 | |
|                 {
 | |
|                     right = ANativeWindow_getWidth(_window),
 | |
|                     bottom = ANativeWindow_getHeight(_window)
 | |
|                 };
 | |
|                 size = new PixelSize(rc.right, rc.bottom);
 | |
|                 ANativeWindow_lock(_window, out buffer, ref rc);
 | |
| 
 | |
|                 root.LayoutManager.ExecuteLayoutPass();
 | |
| 
 | |
|                 var Format = buffer.format == AndroidPixelFormat.WINDOW_FORMAT_RGB_565
 | |
|                     ? CPF.Drawing.PixelFormat.Rgb565 : CPF.Drawing.PixelFormat.Rgba;
 | |
| 
 | |
|                 var RowBytes = buffer.stride * (Format == CPF.Drawing.PixelFormat.Rgb565 ? 2 : 4);
 | |
|                 var Address = buffer.bits;
 | |
| 
 | |
|                 using (Drawing.Bitmap bmp = new Drawing.Bitmap(size.Width, size.Height, RowBytes, Format, Address))
 | |
|                 {
 | |
|                     using (DrawingContext dc = DrawingContext.FromBitmap(bmp))
 | |
|                     {
 | |
|                         if (root.LayoutManager.VisibleUIElements != null)
 | |
|                         {
 | |
|                             //generalView.invalidateRect * RenderScaling
 | |
|                             root.RenderView(dc, new Drawing.Rect(0,0,size.Width,size.Height));
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 ANativeWindow_unlockAndPost(_window);
 | |
|                 ANativeWindow_release(_window);
 | |
|             }
 | |
|             //System.Diagnostics.Debug.WriteLine(stopwatch.ElapsedMilliseconds);
 | |
|         }
 | |
| 
 | |
|         public override IInputConnection OnCreateInputConnection(EditorInfo outAttrs)
 | |
|         {
 | |
|             return generalView.OnCreateInputConnection(outAttrs);
 | |
|         }
 | |
| 
 | |
|         public bool OnKey(View v, [GeneratedEnum] Keycode keyCode, KeyEvent e)
 | |
|         {
 | |
|             generalView.OnKey(v, keyCode, e);
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         public bool OnTouch(View v, MotionEvent e)
 | |
|         {
 | |
|             return generalView.OnTouch(v, e);
 | |
|         }
 | |
| 
 | |
|         //public override bool DispatchKeyEvent(KeyEvent e)
 | |
|         //{
 | |
|         //    //var m = new WindowManagerLayoutParams(100, 100, 100, 100, WindowManagerTypes.Phone | WindowManagerTypes.ApplicationOverlay, WindowManagerFlags.NotFocusable, global::Android.Graphics.Format.Rgbx8888);
 | |
|         //    ////m.Gravity = GravityFlags.Left | GravityFlags.Top;
 | |
|         //    //activity.WindowManager.AddView(new TestView(activity) { Background = new global::Android.Graphics.Drawables.ColorDrawable(global::Android.Graphics.Color.Argb(100, 255, 0, 0)) }, m);
 | |
| 
 | |
| 
 | |
|         //}
 | |
| 
 | |
|         protected override void DispatchSetActivated(bool activated)
 | |
|         {
 | |
|             base.DispatchSetActivated(activated);
 | |
|             //if (activated)
 | |
|             //{
 | |
|             //    (this as IViewImpl).Activated();
 | |
|             //}
 | |
|             //else
 | |
|             //{
 | |
|             //    Deactivated();
 | |
|             //}
 | |
|             generalView.DispatchSetActivated(activated);
 | |
|         }
 | |
| 
 | |
|         [DllImport("android")]
 | |
|         internal static extern IntPtr ANativeWindow_fromSurface(IntPtr jniEnv, IntPtr handle);
 | |
|         [DllImport("android")]
 | |
|         internal static extern int ANativeWindow_getWidth(IntPtr window);
 | |
|         [DllImport("android")]
 | |
|         internal static extern int ANativeWindow_getHeight(IntPtr window);
 | |
|         [DllImport("android")]
 | |
|         internal static extern void ANativeWindow_release(IntPtr window);
 | |
|         [DllImport("android")]
 | |
|         internal static extern void ANativeWindow_unlockAndPost(IntPtr window);
 | |
| 
 | |
|         [DllImport("android")]
 | |
|         internal static extern int ANativeWindow_lock(IntPtr window, out ANativeWindow_Buffer outBuffer, ref ARect inOutDirtyBounds);
 | |
|         public enum AndroidPixelFormat
 | |
|         {
 | |
|             WINDOW_FORMAT_RGBA_8888 = 1,
 | |
|             WINDOW_FORMAT_RGBX_8888 = 2,
 | |
|             WINDOW_FORMAT_RGB_565 = 4,
 | |
|         }
 | |
| 
 | |
|         internal struct ARect
 | |
|         {
 | |
|             public int left;
 | |
|             public int top;
 | |
|             public int right;
 | |
|             public int bottom;
 | |
|         }
 | |
| 
 | |
|         internal struct ANativeWindow_Buffer
 | |
|         {
 | |
|             // The number of pixels that are show horizontally.
 | |
|             public int width;
 | |
| 
 | |
|             // The number of pixels that are shown vertically.
 | |
|             public int height;
 | |
| 
 | |
|             // The number of *pixels* that a line in the buffer takes in
 | |
|             // memory.  This may be >= width.
 | |
|             public int stride;
 | |
| 
 | |
|             // The format of the buffer.  One of WINDOW_FORMAT_*
 | |
|             public AndroidPixelFormat format;
 | |
| 
 | |
|             // The actual bits.
 | |
|             public IntPtr bits;
 | |
| 
 | |
|             // Do not touch.
 | |
|             uint reserved1;
 | |
|             uint reserved2;
 | |
|             uint reserved3;
 | |
|             uint reserved4;
 | |
|             uint reserved5;
 | |
|             uint reserved6;
 | |
|         }
 | |
| 
 | |
| 
 | |
| 
 | |
|         public Screen Screen
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return generalView.Screen;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public float RenderScaling
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 //return global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity;
 | |
|                 return generalView.RenderScaling;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public float LayoutScaling => RenderScaling;
 | |
| 
 | |
|         public Action ScalingChanged { get => generalView.ScalingChanged; set => generalView.ScalingChanged = value; }
 | |
|         public Action<Size> Resized { get => generalView.Resized; set => generalView.Resized = value; }
 | |
|         Action<PixelPoint> IViewImpl.PositionChanged { get => generalView.PositionChanged; set => generalView.PositionChanged = value; }
 | |
|         Action IViewImpl.Activated { get => generalView.Activated; set => generalView.Activated = value; }
 | |
|         public Action Deactivated { get => generalView.Deactivated; set => generalView.Deactivated = value; }
 | |
|         bool IViewImpl.CanActivate { get => generalView.CanActivate; set => generalView.CanActivate = value; }
 | |
|         PixelPoint IViewImpl.Position
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return generalView.Position;
 | |
|             }
 | |
|             set
 | |
|             {
 | |
|                 generalView.Position = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void IViewImpl.Activate()
 | |
|         {
 | |
|             //throw new NotImplementedException();
 | |
|             //RequestFocus();
 | |
|             generalView.Activate();
 | |
|         }
 | |
| 
 | |
|         void IViewImpl.Capture()
 | |
|         {
 | |
|             //RequestPointerCapture();
 | |
|             //throw new NotImplementedException();
 | |
|             generalView.Capture();
 | |
|         }
 | |
| 
 | |
|         void IViewImpl.Invalidate(in Drawing.Rect rect)
 | |
|         {
 | |
|             generalView.Invalidate(in rect);
 | |
|         }
 | |
| 
 | |
|         Drawing.Point IViewImpl.PointToClient(Drawing.Point point)
 | |
|         {
 | |
|             return generalView.PointToClient(point);
 | |
|         }
 | |
| 
 | |
|         Drawing.Point IViewImpl.PointToScreen(Drawing.Point point)
 | |
|         {
 | |
|             return generalView.PointToScreen(point);
 | |
|         }
 | |
| 
 | |
|         void IViewImpl.ReleaseCapture()
 | |
|         {
 | |
|             generalView.ReleaseCapture();
 | |
|         }
 | |
| 
 | |
|         void IViewImpl.SetCursor(Cursor cursor)
 | |
|         {
 | |
|             //throw new NotImplementedException();
 | |
|             generalView.SetCursor(cursor);
 | |
|         }
 | |
| 
 | |
|         //internal bool IMEEnable = true;
 | |
|         void IViewImpl.SetIMEEnable(bool enable)
 | |
|         {
 | |
|             //IMEEnable = enable;
 | |
|             generalView.SetIMEEnable(enable);
 | |
|         }
 | |
| 
 | |
|         //bool showInput;
 | |
|         //internal static IEditor editor;
 | |
|         public void ShowKeyboard(bool show, IEditor editor)
 | |
|         {
 | |
|             generalView.ShowKeyboard(show, editor);
 | |
|         }
 | |
| 
 | |
|         void IViewImpl.SetIMEPosition(Drawing.Point point)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         void IViewImpl.SetRoot(Controls.View view)
 | |
|         {
 | |
|             generalView.SetRoot(view);
 | |
|         }
 | |
| 
 | |
|         void IViewImpl.SetVisible(bool visible)
 | |
|         {
 | |
|             generalView.SetVisible(visible);
 | |
|         }
 | |
| 
 | |
|         protected override void Dispose(bool disposing)
 | |
|         {
 | |
|             eglContext?.Dispose();
 | |
|             eglContext = null;
 | |
|             base.Dispose(disposing);
 | |
|         }
 | |
| 
 | |
|         public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height)
 | |
|         {
 | |
|             pixelSize = new PixelSize(width, height);
 | |
|             eglContext.OnDestroySurface();
 | |
|             eglContext.OnCreateSurface();
 | |
|             //GLES20.GlViewport(0, 0, width, height);
 | |
|         }
 | |
| 
 | |
|         public void SurfaceCreated(ISurfaceHolder holder)
 | |
|         {
 | |
|             eglContext?.OnCreateSurface();
 | |
|         }
 | |
| 
 | |
|         public void SurfaceDestroyed(ISurfaceHolder holder)
 | |
|         {
 | |
|             eglContext?.OnDestroySurface();
 | |
|         }
 | |
|         //public bool OnCapturedPointer(View view, MotionEvent e)
 | |
|         //{
 | |
|         //    System.Diagnostics.Debug.WriteLine(view + "--" + e.Action);
 | |
|         //    return false;
 | |
|         //}
 | |
|     }
 | |
| 
 | |
|     class InnerView : CPF.Controls.View
 | |
|     {
 | |
|         ISurfaceView cpfView;
 | |
|         public InnerView(ISurfaceView cpfView) : base(cpfView)
 | |
|         {
 | |
|             this.cpfView = cpfView;
 | |
|         }
 | |
| 
 | |
|         protected override IViewImpl CreateView()
 | |
|         {
 | |
|             return cpfView;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //class TestView : View
 | |
|     //{
 | |
|     //    public TestView(global::Android.Content.Context context) : base(context)
 | |
|     //    {
 | |
|     //        Focusable = true;
 | |
|     //        FocusableInTouchMode = true;
 | |
|     //    }
 | |
| 
 | |
|     //}
 | |
| } | 
