2017年4月10日 星期一

Android studio 建立Tabbed Activity




上面影片就是Tabbed Activity效果,準備弄個漂亮的介面來寫擷取和錄製Screen的APP
A.
android studio新增Tabbed Activity














B.
public boolean onCreateOptionsMenu(Menu menu)這個methoid 會產生menu表單
要新增menu item在在menu目錄下menu_main.xml來新增(如下圖)
public boolean onOptionsItemSelected(MenuItem item) 處理選單事件



C.
mViewPager.addOnPageChangeListener(...)這是額外加上,處理ViewPaber更改頁面事件,譬如來更改toolbar的title,icon
D.
Fragment:
public View onCreateView(....)這裡來更改ViewPager裡面的原件或內容,
不要用getArguments().getInt(ARG_SECTION_NUMBER)去判斷目前viewPager當前的頁面
E.
FragmentPagerAdapter:
public int getCount() 設定幾個頁面
F.
menu icon不顯示(google上找到)

把MenuBuilder的setOptionalIconsVisible設為true就能顯示icon

values目錄下有styles.xml,string.xml,color.xml,dimens.xml
styles.xml自訂theme
color.xml自訂color對應styles.xml
string.xml自訂的文字
dimens.xml自訂的dimens




icon圖片放在drawable



package com.example.yplin.screenrecorder;
//res-value-styles.xml自訂style對應color.xml
//可將icon png複製到res-drawable,只能使用小寫會底線命名
//appbar的layout_behavior必須添加屬性@string/appbar_scrolling_view_behavior,不被攔截
//toolbar的layout_scroollFlags將scrool取消讓toolbar不能滑動
//增加menu item這裡加入選項,res-menu-menu_main.xml
//讓Icon 顯示,把MenuBuilder的setOptionalIconsVisible設為true就能顯示icon
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.menu.MenuBuilder;
import android.support.v7.widget.Toolbar;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

import android.view.Window;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.lang.reflect.Method;

public class MainActivity extends AppCompatActivity {

            /**     
            * The {@link android.support.v4.view.PagerAdapter} that will provide     
            * fragments for each of the sections. We use a     
            * {@link FragmentPagerAdapter} derivative, which will keep every     
            * loaded fragment in memory. If this becomes too memory intensive, it     
            * may be best to switch to a     
            * {@link android.support.v4.app.FragmentStatePagerAdapter}.     
            */    
    private SectionsPagerAdapter mSectionsPagerAdapter;

    /**     
    * The {@link ViewPager} that will host the section contents.     
    */    
    private  ViewPager mViewPager;
    private static int mpage=0;//一開始第0頁    
    private String recorder_text="左右滑動來選擇錄製或截圖";
    

    @Override    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        // Create the adapter that will return a fragment for each of the three        
        // primary sections of the activity.        
        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
        // Set up the ViewPager with the sections adapter.        
        mViewPager = (ViewPager) findViewById(R.id.container);
        mViewPager.setAdapter(mSectionsPagerAdapter);                            
        toolbar.setTitle("全螢幕截圖");
        toolbar.setLogo(R.drawable.image_recorder);
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);//add a button        
        fab.setOnClickListener(new View.OnClickListener() {
        @Override            
        public void onClick(View view) {                                        //listener  
              //由下而上滑動                
          Snackbar.make(view, recorder_text, Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
                //這裡放截圖事件            }
        });

        //我們用addOnPageChangeListeneraddOnPageChangeListener來取得當前page        
        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override            
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }
            @Override            public void onPageSelected(int position) {
                Log.d("TAG","position:"+position);
                switch(position){
                    case 0:
                        toolbar.setTitle("截屏錄屏服務");
                        toolbar.setLogo(R.drawable.image_recorder);
                        recorder_text="左右滑動來選擇錄製或截圖";
                        break;
                    case 1:
                        toolbar.setTitle("全螢幕截屏");
                        toolbar.setLogo(R.drawable.capture1);
                        recorder_text="開始全螢幕截屏,按左上角開始擷取";
                        break;
                    case 2:
                        toolbar.setTitle("區域螢幕截屏");
                        toolbar.setLogo(R.drawable.ic_phone_android);
                        recorder_text="開始區域螢幕截屏,按左上角開始,點擊螢幕擷取";
                        break;
                    case 3:
                        toolbar.setTitle("全螢幕錄屏");
                        toolbar.setLogo(R.drawable.camera_photo);
                        recorder_text="開始全螢幕錄屏,按左上角開始錄屏";
                        break;
                }
            }
            @Override            public void onPageScrollStateChanged(int state) {

            }
        });




    }   
       //這裡加入選項,res-menu-menu_main.xml    
       @Override    
       public boolean onCreateOptionsMenu(Menu menu) {
        //讓Icon 顯示,把MenuBuilder的setOptionalIconsVisible設為true就能顯示icon        
       if(menu.getClass().getSimpleName().equals("MenuBuilder")){
            try{
                Method m=menu.getClass().getDeclaredMethod("setOptionalIconsVisible",Boolean.TYPE);
                m.setAccessible(true);
                m.invoke(menu,true);
            }catch(Exception e){}
        }

        /**這也行,但有紅線error但可運行        
        if(menu instanceof MenuBuilder){            
           MenuBuilder m=(MenuBuilder) menu;            
           m.setOptionalIconsVisible(true);        }        
         */        
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
    //這裡處理選項事件        
    @Override    
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will        
        // automatically handle clicks on the Home/Up button, so long        
        // as you specify a parent activity in AndroidManifest.xml.        
        int id = item.getItemId();
        Log.d("TAG MENU ID",String.valueOf(id));
        Log.d("TAG action ID",String.valueOf(R.id.menu2));
        //根據選項切換viewpager        
        if (id == R.id.menu1) {mViewPager.setCurrentItem(0,true);}//return true;}        
        if (id == R.id.menu2) {mViewPager.setCurrentItem(2,true);}//return true;}        
        if (id == R.id.menu3) {mViewPager.setCurrentItem(3,true);}//return true;}        
        if (id == R.id.menu4) {mViewPager.setCurrentItem(1,true);}//return true;}        
        return super.onOptionsItemSelected(item);
       }
        /**     
        * A placeholder fragment containing a simple view.     
        */    
        public static class PlaceholderFragment extends Fragment {
        /**         
        * The fragment argument representing the section number for this         
        * fragment.         
        */        
        private static final String ARG_SECTION_NUMBER = "section_number";
        //private static final String ARG_SECTION_NUMBER = "ARG_PAGE";        
        private RelativeLayout mrelativelayout;  //主容器        
        private TextView mtextView;
        private View rootView=null;
        public PlaceholderFragment() {

        }

        /**         
        * Returns a new instance of this fragment for the given section         
        * number.         
        */        
        public static PlaceholderFragment newInstance(int sectionNumber) {
            //PlaceholderFragment fragment = new PlaceholderFragment();            
            Bundle args = new Bundle();
            args.putInt(ARG_SECTION_NUMBER, sectionNumber);
            PlaceholderFragment fragment = new PlaceholderFragment();
            fragment.setArguments(args);
            return fragment;
        }

        @Override        
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            if(rootView==null) {
                rootView = inflater.inflate(R.layout.fragment_main, container, false);
            }
            mrelativelayout=(RelativeLayout) rootView.findViewById(R.id.RL);
            mtextView = (TextView) rootView.findViewById(R.id.textView);
            //mtextView.setText(getString(R.string.section_format, getArguments().getInt(ARG_SECTION_NUMBER)));            
            //注意不能用getArguments().getInt(ARG_SECTION_NUMBER)取得當前page取得當前page            
            //因為這會下到欲轉的頁面一開始會是0,1            
            //我們用addOnPageChangeListeneraddOnPageChangeListener來取得當前page            
            //textView.setText(String.valueOf(getArguments().getInt(ARG_SECTION_NUMBER)));            
            mrelativelayout.removeAllViews();//一開始先清除頁面上所有元件            
            //根據頁面需要加上元件            
            if(getArguments().getInt(ARG_SECTION_NUMBER)==1){add_pag1(rootView);}
            if(getArguments().getInt(ARG_SECTION_NUMBER)==2){add_pag2(rootView);}
            if(getArguments().getInt(ARG_SECTION_NUMBER)==3){add_pag3(rootView);}
            if(getArguments().getInt(ARG_SECTION_NUMBER)==4){add_pag4(rootView);}
            //Log.d("TAG",String.valueOf(getArguments().getString("title")));            
            //if(getArguments().getInt(ARG_SECTION_NUMBER)==2){add_pag2(rootView);}            
            return rootView;
        }
        //頁面1,新增元件位置時,xml不要相對會變動的元件,否則位置會跑掉        
        private void add_pag1(View v){
            mrelativelayout.removeAllViews();
            mrelativelayout.addView(mtextView);
            mtextView.setText("作者:Y.P.LIN");
            Log.d("TAG","screen 4");
        }
        //頁面2,新增元件位置時,xml不要相對會變動的元件,否則位置會跑掉        
        private void add_pag2(View v){
            mrelativelayout.removeAllViews();
            mrelativelayout.addView(mtextView);
            mtextView.setText("全螢幕截圖");
            Log.d("TAG","screen 1");
        }
        //頁面3,新增元件位置時,xml不要相對會變動的元件,否則位置會跑掉        
        private void add_pag3(View v){
            mrelativelayout.removeAllViews();
            mrelativelayout.addView(mtextView);
            mtextView.setText("區域螢幕截圖");
            Log.d("TAG","screen 2");

        }
        //頁面4,新增元件位置時,xml不要相對會變動的元件,否則位置會跑掉        
        private void add_pag4(View v){
            mrelativelayout.removeAllViews();
            mrelativelayout.addView(mtextView);
            mtextView.setText("全螢幕錄屏");
            Log.d("TAG","screen 3");
        }
    }//class  PlaceholderFragment
    /**     
    * A {@link FragmentPagerAdapter} that returns a fragment corresponding to     
    * one of the sections/tabs/pages.     */    
    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override        
        public Fragment getItem(int position) {
            // getItem is called to instantiate the fragment for the given page.            
            // Return a PlaceholderFragment (defined as a static inner class below).            
           return PlaceholderFragment.newInstance(position + 1);
        }
        //幾個頁面        @Override        public int getCount() {
            // Show 3 total pages.            return 4;
        }
        @Override        public CharSequence getPageTitle(int position) {
            switch (position) {
                case 0:
                    return "SECTION 0";
                case 1:
                    return "SECTION 1";
                case 2:
                    return "SECTION 2";
                case 3:
                    return "SECTION 3";

            }
            return null;
        }
    }
}

read more...

2017年4月4日 星期二

android5.0以上,用MediaProjection API 錄製螢幕畫面




上一篇說到Android 手機不用root,要如何捕抓螢幕,這次講要如何錄製,跟上一篇幾乎一樣,捕捉螢幕是得到ImageRecorder,錄製畫面改成MediaRecorder就可以,但要先初始化這個MediaRecorder,我把它放在這個init_media_recorder()只是設定一些資訊,但AndroidManifest記得給android.permission.RECORD_AUDIO權限,mMediaRecorder.prepare();準備完mMediaRecorder.start();就開始錄製了,記得VirtualDisplay放在onActivityResult method是較正確的,上篇有說到為什麼.

錄製畫面,其實很簡單,看網路上的例子繞來繞去,真不好搞懂,我把它整理一下很容易看懂,上面影片,就是用MediaProjection API錄製的,畫面很好,聲音不知為什很差,可能是解碼器的關係,這我就不曉得了,應該是透過麥克風錄音的關係!!


    private MediaProjectionManager mpm;
    private MediaProjection mp;
    private VirtualDisplay vp_recorder=null;//recorder screen
    private MediaRecorder mMediaRecorder;
    //private static final int REQUEST_NUMBER=1001;
    private static final int REQUEST_NUMBER=1;



     mMediaRecorder=new MediaRecorder();  //
  mpm=(MediaProjectionManager)getSystemService(MEDIA_PROJECTION_SERVICE); //media projection manager
     startActivityForResult(mpm.createScreenCaptureIntent(),REQUEST_NUMBER); //開始授權media projection



    @Override
    public void onActivityResult(int requestCode,int resultCode,Intent data){

        if(REQUEST_NUMBER==requestCode) {
            if (resultCode != RESULT_OK) {
                Toast.makeText(this, "USER CANCELLED", Toast.LENGTH_LONG).show();
                return;
            }
            DisplayMetrics ds = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(ds);
            int dpi = ds.densityDpi;
            int dw = ds.widthPixels;
            int dh = ds.heightPixels;
            mp = mpm.getMediaProjection(resultCode, data);
            //B.螢幕錄製,AndroidManifest記得給android.permission.RECORD_AUDIO
            if (vp_recorder == null) {//只是確保一個virtual display
                //mMediaRecorder = new MediaRecorder();                                     //這個螢幕錄製,這個和capture screen不相干
                init_media_recorder();             //初始化media recorder
                prepare_media_recorder();      //準備錄製
                //建立虛擬display for recorder screen
                vp_recorder = mp.createVirtualDisplay("ScreenRecorder", dw, dh, dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null);

            }

        }
    }



//////////////////////////////recorder screen////////////////////////////////////////////////////////////////////

    public void start_Recorder(View v){
        //init_media_recorder();         //初始化media recorder
        //prepare_media_recorder();      //準備錄製
        mMediaRecorder.start();        //開始錄製
        this.moveTaskToBack(true);   //app退到後台
    }
    public void stop_Recorder(View v){
        mMediaRecorder.stop();         //停止錄製
        mMediaRecorder.reset();
        this.show_app();
    }

    //初始化media recorder,AndroidManifest記得給android.permission.RECORD_AUDIO
    private void init_media_recorder() {
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);    //音源
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);//影源
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);//格式
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);  //影像解碼器
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//音源解碼器
        mMediaRecorder.setVideoEncodingBitRate(512*1000);                 //解碼率
        mMediaRecorder.setVideoFrameRate(30);                             //視窗更新頻率
        mMediaRecorder.setVideoSize(480,640);                             //影像寬高
        mMediaRecorder.setOutputFile("/sdcard/capture.mp4");              //儲存路徑
    }
//準備錄製
    private void prepare_media_recorder(){
        try {
            mMediaRecorder.prepare();
        }
        catch(Exception e)
        {
            e.printStackTrace();
            finish();
        }
    }



read more...

2017年4月2日 星期日

Android5.0 使用mediaProjection抓取手機螢幕





花了ㄧ些時間,不用root手機,要如何用android java程式抓取手機螢幕的畫面,最後找到android5.0以上版本,我們可以使用mediaProjectio這個API來截取螢幕或錄制螢幕,首先要實作onActivity這個method,要讓使用者決定是否要啟用,會出現對話框,使用者按確定後,取得ImageReader就可做後續處理,若使用者按Canselled就不能使用mediaProjection來截取螢幕,google開放這樣做法,就不會有隱私權的問題,上面影片我還使用windowmanager來達成抓取開啟任何app,都能截取畫面,一開使按確定,使用者開啟瀏覽器,按左上角play,點擊螢幕截取框框中畫面,加到左下角主頁面中的image view,按左上角離開,就會跳回主頁面看到截圖,目前整個程式,我還沒寫很完整,寫好在放上來,寫到這樣都是google上找的資料。

補充一下,這個VirtualDisplay,是在onActivityResult中初始化,才是正確的,不是在事件中去初始化,這樣程式app,只會產生一個VirtualDisplay,若是在事件中初始化,或放在執行緒,那就會產生太多的VirtualDisplay,會導致內存問題的.
            vp=mp.createVirtualDisplay(..........................);
就我的意識,這VirtualDisplay和機器螢幕是同步,獲取ImgaeReader就是即時的.
        

A.實作onActivityResult讓使用者對話開始使用mediaProjection

MyActivity:
    ............
    private MediaProjectionManager mpm;
    private MediaProjection mp;
    private ImageReader ir=null;
    private VirtualDisplay vp;
    private static final int REQUEST_NUMBER=1001;
    .....................
    mpm=(MediaProjectionManager)getSystemService(MEDIA_PROJECTION_SERVICE);
    startActivityForResult(mpm.createScreenCaptureIntent(),REQUEST_NUMBER);
    .....................
    //讓使用者決定可以使用mediaProjection,跳出對話框,使用者按OK,便可使用ir抓取screen picture,否則return
    @Override
    public void onActivityResult(int requestCode,int resultCode,Intent data){

        if(REQUEST_NUMBER==requestCode){
            if(resultCode!=RESULT_OK){
                Toast.makeText(this,"USER CANCELLED",Toast.LENGTH_LONG).show();
                return;
            }
            DisplayMetrics ds=new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(ds);
            int dpi=ds.densityDpi;
            int dw=ds.widthPixels;
            int dh=ds.heightPixels;
            mp=mpm.getMediaProjection(resultCode,data);
            ir=ImageReader.newInstance(dw,dh, PixelFormat.RGBA_8888,2);
            //建立虛擬display
            vp=mp.createVirtualDisplay("ScreenCapture",dw,dh,dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,ir.getSurface(),null,null);
        }

B.取得ImageReader後,做後續Bitmap處理

package com.example.yplin.myapplication11;

import android.graphics.Bitmap;
import android.media.ImageReader;
import android.media.Image;
import android.util.Log;
import java.nio.ByteBuffer;

/**
 * Created by yplin on 2017/3/31.
 * 截取螢幕畫面
 * Activity必須決定可以使用mediaProjection
 * 產生一個ImageReader來截取螢幕畫面
 */

public class capture_screen {
    private MainActivity11 MainA=null;
private Bitmap bp=null;
    public  capture_screen(MainActivity11 ma){
        MainA=ma;
        if(ma.get_imagereader()!=null){
            ImageReader ir=ma.get_imagereader(); //image reader
            int dw=ma.get_screen_width();        //screen width
            int dh=ma.get_screen_height();       //screen height
            Image mimage = ir.acquireLatestImage();
            Image.Plane[] planes = mimage.getPlanes();
            ByteBuffer buffer = planes[0].getBuffer();
            int ps = planes[0].getPixelStride();
            int rs = planes[0].getRowStride();
            int rp = rs - ps * dw;
            bp = Bitmap.createBitmap(dw + rp / ps, dh, Bitmap.Config.ARGB_8888);
            bp.copyPixelsFromBuffer(buffer); //full screen picture
            mimage.close();
        }else{
            Log.d("USAGE:", "使用者必須決定可以使用mediaProjection");
        }
    }
    //BUG x+w不能大於screen width y+h 不能大於screen height,x和y不能小於0
    //Region Screem picture
    public Bitmap get_bitmap(int x,int y,int w,int h){
        MainA.add_image(bp.createBitmap(bp,x,y,w,h));  //把Region Screen 放置Activity的image view
        return bp.createBitmap(bp,x,y,w,h);            //Return Region Screen
    }
    public void clear_bitmap(){bp=null;}

read more...

2017年3月15日 星期三

android app背景的touch事件

android app背景的touch事件,在網路上有資料,整理一下

1.
AndroidManifest.xml要給權限,加入

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />



AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yplin.myapplication11">
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.VIBRATE" />


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity11">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".floatActivity"></activity>
    </application>

</manifest>


2.
取得WindowManager(是一個更上層的obj,可google一下)
建立dunmmy view(空的view)
設置LayoutParams
根據LayoutParams將dummy view加mWindowManager



package com.example.yplin.myapplication11;

import android.graphics.PixelFormat;


import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

import android.view.MotionEvent;
import android.view.View;

import android.view.WindowManager;
import android.widget.LinearLayout;

//繼承AppCompatActivityAppCompatActivity實做OnTouchListener
public class MainActivity11 extends AppCompatActivity implements   View.OnTouchListener {

    private LinearLayout lc=null;
    private CustomView1 canvas_view =null;
    @Override    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main11);
        lc=(LinearLayout)findViewById(R.id.view1);
        canvas_view = new CustomView1(this);
        Context mContext=getApplicationContext();
        // 取得WindowManagerWindowManager        
        WindowManager mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        //建立一個dummy的view        
        LinearLayout mDummyView = new LinearLayout(mContext);
        //新設置LayoutParams叫params,注意androidManifest.xml需給權限        
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                1, /* width */                1, /* height */                
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSPARENT        );
        //可更改dummy view設置params        
        //mDummyView.setLayoutParams(params);        
        //dummy view設置touch傾聽事件        
        mDummyView.setOnTouchListener(this);
        //根據params將dummy view加mWindowManager
        mWindowManager.addView(mDummyView, params);
    }
    //實作OnTouchListener的onTouch傾聽事件方法    
        @Override    
        public boolean onTouch(View v, MotionEvent event) {
        //LinearLayout lc=(LinearLayout)findViewById(R.id.view1);        
        if(lc.indexOfChild(canvas_view)==-1) {

            lc.addView(canvas_view);
        }
        else        {
            lc.removeAllViews();
        }
        return false;
    }

    class CustomView1 extends View{

        Paint paint;

        public CustomView1(Context context) {
            super(context);
            paint = new Paint();                   //設置一新畫筆            
            paint.setColor(Color.RED);             //黄色            
            paint.setStrokeJoin(Paint.Join.ROUND);
            paint.setStrokeCap(Paint.Cap.ROUND);
            paint.setStrokeWidth(3);               //設置一筆刷大小3        }

        //create circle        
        @Override        
        protected void onDraw(Canvas canvas) {

            canvas.drawCircle(100, 100, 90, paint);

        }

    }
}


實際結果,背景下觸摸螢幕,touch事件被這app接收了


















































read more...

2017年3月12日 星期日

用SIKULI去android手機內抓圖做點擊

一般網路上看到的,都是用電腦接手機投射到電腦螢幕,抓電腦手機螢幕的圖,在外國網站有人用sikuli直接去手機內抓螢幕的圖,控制手機,而不是在電腦螢幕去做控制,終於試出來了,你要先安裝adb,若你有安裝android studio,其實就有adb了,在安裝目錄下.../Android/sdk/platform-tools/adb device -l

1.
terminal下執行下面指令連接手機

../Android/sdk/platform-tools/adb device -l

2.
sikuli API android目錄有一個ADBScreen class,import它,叫用start函式,會傳回android螢幕物件screen,我們就可在android手機內做動作,譬如螢幕抓圖,螢幕點擊.....等,下面是一個簡單抓圖和螢幕點擊

import org.sikuli.android.ADBScreen as Ascreen #把ADBScreen直接設成Ascreen
x=Ascreen.start()      #傳回androi screen


3.
SIKULI-IDE的python程式

#####################convert######################
#請用android studio看jar的程式
assert load('/Users/yplin/sikulix.jar')
import org.sikuli.android.ADBScreen as Ascreen #把ADBScreen直接設成Ascreen
import subprocess
#有安裝android studio找到adb用adb devices -l連接手機
#subprocess.call("/Users/yplin/Library/Android/sdk/platform-tools/adb devices -ladb devices -l".split())
#import org.sikuli.android.ADBClient as Aclient
#print(Aclient.getDevice())

x=Ascreen.start()      #傳回androi screen
use(x)                 #use
x.needsUnLock = False
wakeUp(2)
#store_path_base = os.getenv("HOME")
#new_path=os.path.join(store_path_base,"SIKULI/PNG/t.png")
new_path="/Users/yplin"
reg=x.newRegion(0,0,1000,1000)  #手機區域region
#reg.highlight(1)
img=x.capture(reg)      #抓手機螢幕圖
click(reg)              #點擊手機螢幕
img.save(new_path)      #存檔

popup("capture picture ok")

抓到圖的結果(左邊下面的小圖):

read more...

2016年7月22日 星期五

SKILL寫的可做出各種SUB RING

使用ROD寫出SUB RIN,可畫出N RING ,P RING,SINGLE RING,DOUBLE RING,DOUBLE RING可指定RING是P在內側或外側,CONTACT各要幾排


ENTER PATH SINGLE RING



ENTER BOX DOUBLE RING

 ENTER BOX DOUBLE RING設M1可chop,其它不可chop






read more...

2016年1月30日 星期六

想念的加州公園

這是第四次來美國了,己經來一個月了,上上星期,到單車店刷卡400多美金,買了一輛單車來騎,這星期六,自己騎著單車到公園散心,天氣不錯,躺在公園的草地上,中午有出一些太陽,很溫暖,左公園繞一陣子,看見鴨子在濕地,游來游夫,悠閒的樣子。

 想到以前來美國住的旅館晃晃,沿著單車道騎,想到以前住旅館時,假日都是走這,小跑步到公園散心,有著許多回憶,好懷念啊,下午4點多了,去附近吃飯,回到住的己經5點多了。
拍了一些照片,留下紀念





read more...