About device orientation

本文介绍如何在iOS和Android上设置设备方向。提供了两种方法:OpenGL/cocos2d-x方式,适用于仅旋转由cocos引擎渲染的对象;ViewController方式(iOS)或通过XML设置(Android),适用于旋转UIKit对象或小部件。

About device orientation

This article describes how to set device orientation on iOS and android.
As you know, there are two ways to set device orientation:
  • The OpenGL / cocos2d-x way
    Faster, but doesn't rotate the UIKit objects(iOS) or widgets(android).
  • The ViewController way(iOS) or set by xml(android)
    A bit slower, but the UIKit objects(iOS) or widgets(android) are placed in the right place.

The OpenGL way

You can set device orientation as follows:

CCDirector::sharedDirector()->setDeviceOrientation(kCCDeviceOrientationLandscapeLeft);

This way can only rotate objects rendered by the cocos engine, such as sprites or labels.

ViewController way(iOS)

The device orientation takes effect as follows:
  • Tell the system which orientations the application supports(RootViewController.mm)
    // Override to allow orientations other than the default landscape orientation.
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        return UIInterfaceOrientationIsLandscape( interfaceOrientation );
    }
    
  • Add the view OpenGL rendered to the root view controller(AppController.mm)
    // Use RootViewController manage EAGLView 
        viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
        viewController.wantsFullScreenLayout = YES;
        viewController.view = __glView;
    

The code is implemented in cocos2d-x as an iOS template.

Set device orientation in AndroidManifest.xml(android)

<application android:label="@string/app_name" android:debuggable="true" android:icon="@drawable/icon">
        <activity android:name=".ApplicationDemo" 
                  android:label="@string/app_name" 
                  android:screenOrientation="landscape" 
                  android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 
                  android:configChanges="orientation">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

Conclusions

1. If you want to use OpenGL approach in iOS, don't use RootViewController.
2. If you want to use OpenGL way in Android, set the orientation to portrait in AndroidManifest.xml.
3. If you don't use any UIKit objects(iOS) or widgets(android) at all, then using OpenGL directly will be faster.

Supporting multiple orientations

Apply the following workaround to support multiple orientations as of cocos2d-x v2.0.2.
This patch may not be supported in future releases of cocos2d-x, or may become partially deprecated.

iOS

1. Comment out assert(m_eResolutionPolicy  kResolutionUnKnown); in cocos2dx/platform/ios/CCEGLView.mm::setContentScaleFactor(...).
2. Comment out CCAssert(m_bIsRetinaEnabled  false, "can not enable retina while set design resolution size!"); in cocos2dx/platform/CCEGLViewProtocol.cpp::setDesignResolutionSize(...).
3. Return true in shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation.
4. In (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation, add:

CGSize s;
if (UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)) {
  s = CGSizeMake(std::max<float>(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height), std::min<float>(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height));
} else {
  s = CGSizeMake(std::min<float>(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height), std::max<float>(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height));
}

cocos2d::CCDirector* director = cocos2d::CCDirector::sharedDirector();
director->enableRetinaDisplay(false);
director->getOpenGLView()->setFrameSize(s.width, s.height);
director->getOpenGLView()->setDesignResolutionSize(s.width, s.height, kResolutionShowAll);
director->enableRetinaDisplay(true);

Android

1. Add nativeInit(w, h); to cocos2dx/platform/android/java/src_common/org/cocos2dx/lib/Cocos2dxRenderer.java -> void onSurfaceChanged(GL10 gl, int w, int h).
2. Add this code to void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thiz, jint w, jint h):

cocos2d::CCEGLView* view = cocos2d::CCDirector::sharedDirector()->getOpenGLView();
if (!view) {
  ...
} else {
  ...
  if (view->getFrameSize().width != w || view->getFrameSize().height != h) {
    view->setFrameSize(w, h);
    view->setDesignResolutionSize(w, h, kResolutionShowAll);
  }
}

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!--Device Share --> <com.tplink.design.card.TPConstraintCardView android:id="@+id/cv_device_share" style="@style/setting_tp_constraint_cardview_top_16dp"> <RelativeLayout android:id="@+id/rl_setting_device_share" android:layout_width="match_parent" android:layout_height="wrap_content"> <com.tplink.design.list.TPSingleLineItemView android:id="@+id/line1_setting_device_share" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="false" app:itemTitle="@string/setting_device_share" android:layout_alignParentStart="true" android:layout_alignParentEnd="true" android:layout_toStartOf="@+id/setting_device_share_item_right_tv" android:layout_centerVertical="true"/> <ImageView android:id="@+id/setting_device_share_item_right_iv" style="@style/setting_device_share_user_image" android:layout_toStartOf="@+id/setting_device_share_item_right_tv" /> <TextView android:id="@+id/setting_device_share_item_right_tv" style="@style/setting_device_share_user_text" android:layout_toStartOf="@+id/iv_setting_device_share_next" /> <ImageView android:id="@+id/iv_setting_device_share_next" style="@style/setting_item_next_image" android:layout_alignParentEnd="true" /> </RelativeLayout> </com.tplink.design.card.TPConstraintCardView> <com.tplink.design.card.TPConstraintCardView android:id="@+id/cv_device_info" style="@style/setting_tp_constraint_cardview_top_16dp"> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_connection" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="connection" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@id/line2_device_model" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_model" style="@style/setting_tp_line_item_view" app:itemTitle="@string/setting_about_device_model" app:layout_constraintTop_toBottomOf="@id/line2_device_connection" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_setting_firmware_item" style="@style/setting_tp_line_item_view_next" app:itemTitle="@string/setting_firmware_version" app:layout_constraintTop_toBottomOf="@id/line2_device_model"/> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_sn" style="@style/setting_tp_line_item_view" app:itemTitle="sn" app:layout_constraintTop_toBottomOf="@id/line2_setting_firmware_item" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_id" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="@string/device_add_id_input_guide_device_id_hint" app:layout_constraintTop_toBottomOf="@id/line2_device_sn" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_ip_address" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="@string/setting_about_recorder_ip_address" app:layout_constraintTop_toBottomOf="@id/line2_device_id" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_mac_address" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="@string/setting_about_recorder_mac_address" app:layout_constraintTop_toBottomOf="@id/line2_device_ip_address" /> <com.tplink.design.list.TPTwoLineItemView style="@style/setting_tp_line_item_view" android:id="@+id/line2_device_resolution" app:itemTitle="Resolution" app:layout_constraintTop_toBottomOf="@id/line2_device_mac_address" /> <com.tplink.design.list.TPTwoLineItemView style="@style/setting_tp_line_item_view" android:id="@+id/line2_device_frame_rate" app:itemTitle="Resolution" app:layout_constraintTop_toBottomOf="@id/line2_device_resolution" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_up_time" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="Up Time" app:layout_constraintTop_toBottomOf="@id/line2_device_frame_rate" /> </com.tplink.design.card.TPConstraintCardView> </LinearLayout> 这是xml文件,我需要你给我初始化这个xml文件中的所有组件
01-05
package com.example.net; import androidx.activity.result.ActivityResult; import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import android.annotation.TargetApi; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.ImageFormat; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CaptureRequest; import android.media.Image; import android.media.ImageReader; import android.media.MediaScannerConnection; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.provider.MediaStore; //import android.support.annotation.NonNull; //import android.support.v4.app.ActivityCompat; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import androidx.activity.EdgeToEdge; import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.Locale; import java.util.Map; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Headers; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; public class MainActivity extends AppCompatActivity { private ActivityResultLauncher<Intent> activityResultLauncher; private static final int CODE_SELECT_IMAGE = 1; private CameraManager mCameraManager; private SurfaceView mSurfaceView; private SurfaceHolder mSurfaceViewHolder; private Handler mHandler; private String mCameraId; private ImageReader mImageReader; private CameraDevice mCameraDevice; private CaptureRequest.Builder mPreviewBuilder; private CameraCaptureSession mSession; private ImageView img_show; private Button take_picture_bt, mOpenPhoto, mUploadPhoto; private Handler mainHandler; private static final String TAG = "CameraFragment"; private String mPublicPhotoPath = ""; //创建okHttpClient对象 OkHttpClient mOkHttpClient = new OkHttpClient(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.hide(); } img_show = (ImageView) findViewById(R.id.img_show); take_picture_bt = (Button) findViewById(R.id.take_picture); mOpenPhoto = (Button) findViewById(R.id.recognition_open_photo); mUploadPhoto = (Button) findViewById(R.id.recognition_upload_photo); mUploadPhoto.setEnabled(false); // 注册 Activity Result Launcher activityResultLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { if (result.getResultCode() == RESULT_OK) { Intent data = result.getData(); if (data != null) { Uri selectImageUri = data.getData(); String[] filePathColumn = {MediaStore.Images.Media.DATA}; Cursor cursor = getContentResolver().query(selectImageUri, filePathColumn, null, null, null); if (cursor != null) { cursor.moveToFirst(); int columnIndex = cursor.getColumnIndex(filePathColumn[0]); String picturePath = cursor.getString(columnIndex); cursor.close(); img_show.setImageBitmap(BitmapFactory.decodeFile(picturePath)); mPublicPhotoPath = picturePath; mUploadPhoto.setEnabled(true); } } } } }); initSurfaceView();//初始化SurfaceView /** * 拍照按钮监听 */ take_picture_bt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { takePicture(); } }); mOpenPhoto.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent albumIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); // 使用 Activity Result Launcher 启动活动 activityResultLauncher.launch(albumIntent); } }); mUploadPhoto.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 通过AlertDialog.Builder这个类来实例化我们的一个AlertDialog的对象 AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); // 设置Title的图标 builder.setIcon(R.drawable.ic_launcher_background); // 设置Title的内容 builder.setTitle("提示框"); // 设置Content来显示一个信息 builder.setMessage("确定上传吗?"); // 设置一个PositiveButton builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Log.i(TAG, mPublicPhotoPath); if (mPublicPhotoPath == "") { return; } File file = new File(mPublicPhotoPath); Request request = getFileRequest("http://192.168.11.13:10004/api/upload", file, null); Call call = mOkHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.i(TAG, "上传失败!"); } @Override public void onResponse(Call call, Response response) throws IOException { String result = response.body().string(); parseJSONWithGSON(result); //显示UI界面,调用的showResponse方法 Log.i(TAG, result.toString()); //Toast.makeText(MainActivity.this, "success!", Toast.LENGTH_SHORT).show(); } }); } }); // 设置一个NegativeButton builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //Toast.makeText(MainActivity.this, "negative: " + which, Toast.LENGTH_SHORT).show(); } }); // 设置一个NeutralButton // 显示出该对话框 builder.show(); } }); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; }); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(requestCode == 1){ for (int grantResult : grantResults) { if(grantResult != PackageManager.PERMISSION_GRANTED){ Toast.makeText(this, "对不起,没有权限,无法正常使用相机", Toast.LENGTH_SHORT).show(); return; }else{ System.out.println("正常使用相机!"); } } initCameraAndPreview(); } } public void initSurfaceView() { mSurfaceView = (SurfaceView) findViewById(R.id.mFirstSurfaceView); mSurfaceViewHolder = mSurfaceView.getHolder();//通过SurfaceViewHolder可以对SurfaceView进行管理 mSurfaceViewHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { initCameraAndPreview(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { //释放camera if (mCameraDevice != null) { mCameraDevice.close(); mCameraDevice = null; } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } }); } @TargetApi(19) public void initCameraAndPreview() { HandlerThread handlerThread = new HandlerThread("My First Camera2"); handlerThread.start(); mHandler = new Handler(handlerThread.getLooper()); mainHandler = new Handler(getMainLooper());//用来处理ui线程的handler,即ui线程 mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE); try { mCameraId = "" + CameraCharacteristics.LENS_FACING_FRONT; mImageReader = ImageReader.newInstance(mSurfaceView.getWidth(), mSurfaceView.getHeight(), ImageFormat.JPEG,/*maxImages*/7); mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mainHandler);//这里必须传入mainHandler,因为涉及到了Ui操作 if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{android.Manifest.permission.CAMERA, android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); } } return; } mCameraManager.openCamera(mCameraId, deviceStateCallback, mHandler); } catch (CameraAccessException e) { Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show(); } } private ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { //进行相片存储 //mCameraDevice.close(); Image image = reader.acquireNextImage(); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes);//将image对象转化为byte,再转化为bitmap final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); if (bitmap != null) { img_show.setImageBitmap(bitmap); mUploadPhoto.setEnabled(true); } savePicture(bytes); } }; private CameraDevice.StateCallback deviceStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { mCameraDevice = camera; try { takePreview(); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onDisconnected(@NonNull CameraDevice camera) { if (mCameraDevice != null) { mCameraDevice.close(); mCameraDevice = null; } } @Override public void onError(CameraDevice camera, int error) { Toast.makeText(MainActivity.this, "打开摄像头失败", Toast.LENGTH_SHORT).show(); } }; public void takePreview() throws CameraAccessException { mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewBuilder.addTarget(mSurfaceViewHolder.getSurface()); mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceViewHolder.getSurface(), mImageReader.getSurface()), mSessionPreviewStateCallback, mHandler); } private CameraCaptureSession.StateCallback mSessionPreviewStateCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { mSession = session; //配置完毕开始预览 try { /** * 设置你需要配置的参数 */ //自动对焦 mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); //打开闪光灯 mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); //无限次的重复获取图像 mSession.setRepeatingRequest(mPreviewBuilder.build(), null, mHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { Toast.makeText(MainActivity.this, "配置失败", Toast.LENGTH_SHORT).show(); } }; public void takePicture() { try { CaptureRequest.Builder captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);//用来设置拍照请求的request captureRequestBuilder.addTarget(mImageReader.getSurface()); // 自动对焦 captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 自动曝光 captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); int rotation = getWindowManager().getDefaultDisplay().getRotation(); CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId); captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getJpegOrientation(cameraCharacteristics, rotation));//使图片做顺时针旋转 CaptureRequest mCaptureRequest = captureRequestBuilder.build(); mSession.capture(mCaptureRequest, null, mHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } //获取图片应该旋转的角度,使图片竖直 public int getOrientation(int rotation) { switch (rotation) { case Surface.ROTATION_0: return 90; case Surface.ROTATION_90: return 0; case Surface.ROTATION_180: return 270; case Surface.ROTATION_270: return 180; default: return 0; } } //获取图片应该旋转的角度,使图片竖直 private int getJpegOrientation(CameraCharacteristics c, int deviceOrientation) { if (deviceOrientation == android.view.OrientationEventListener.ORIENTATION_UNKNOWN) return 0; int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION); // Round device orientation to a multiple of 90 deviceOrientation = (deviceOrientation + 45) / 90 * 90; // LENS_FACING相对于设备屏幕的方向,LENS_FACING_FRONT相机设备面向与设备屏幕相同的方向 boolean facingFront = c.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT; if (facingFront) deviceOrientation = -deviceOrientation; // Calculate desired JPEG orientation relative to camera orientation to make // the image upright relative to the device orientation int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360; return jpegOrientation; } //将照片存储在相机照片存储位置,这里采用bitmap方式保存 public String savePicture(byte[] imgBytes) { Log.i(TAG, "path:" + "666666"); String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date()); String imgPath = Environment.getExternalStorageDirectory() + "/DCIM/JPEG" + timeStamp + ".jpg"; Log.i(TAG, "path:" + imgPath); Bitmap bitmap = BitmapFactory.decodeByteArray(imgBytes, 0, imgBytes.length);//图像数据被转化为bitmap File outputImage = new File(imgPath); FileOutputStream outputStream = null; try { if (outputImage.exists()) { outputImage.delete();//存在就删除 } outputImage.createNewFile(); } catch (IOException e) { e.printStackTrace(); } try { outputStream = new FileOutputStream(outputImage); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);//第二个参数为压缩质量 Log.i(TAG, "path:" + "7777777"); } catch (FileNotFoundException e) { e.printStackTrace(); } try { outputStream.flush(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } mPublicPhotoPath = imgPath; //及时更新到系统相册 MediaScannerConnection.scanFile(this, new String[]{Environment.getExternalStorageDirectory() + "//DCIM//JPEG" + timeStamp + ".jpg"}, null, null);//"//"可以用File.separator代替 return imgPath; } public static Request getFileRequest(String url, File file, Map<String, String> maps){ MultipartBody.Builder builder= new MultipartBody.Builder().setType(MultipartBody.FORM); if(maps==null){ builder.addPart( Headers.of("Content-Disposition", "form-data; name=\"file\";filename=\"file.jpg\""), RequestBody.create(MediaType.parse("image/png"),file) ).build(); }else{ for (String key : maps.keySet()) { builder.addFormDataPart(key, maps.get(key)); } builder.addPart( Headers.of("Content-Disposition", "form-data; name=\"file\";filename=\"file.jpg\""), RequestBody.create(MediaType.parse("image/png"),file) ); } RequestBody body=builder.build(); return new Request.Builder().url(url).post(body).build(); } private void parseJSONWithGSON(String jsonData) { //使用轻量级的Gson解析得到的json Gson gson = new Gson(); UploadResult uploadResult = gson.fromJson(jsonData, new TypeToken<UploadResult>() {}.getType()); //控制台输出结果,便于查看 Log.d("MainActivity", "status" + uploadResult.getStatus()); Log.d("MainActivity", "msg" + uploadResult.getMsg()); } } 分析上述代码中所有函数的功能
05-23
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/tpds_all_dp_20" android:orientation="vertical"> <com.tplink.design.card.TPConstraintCardView android:id="@+id/cv_solar_battery_info" style="@style/setting_tp_constraint_cardview_top_16dp"> <com.tplink.ipc.common.CircleProgressView android:id="@+id/progress_view_power" android:layout_width="@dimen/tpds_all_dp_150" android:layout_height="@dimen/tpds_all_dp_150" android:layout_marginTop="@dimen/tpds_all_dp_16" android:layout_marginBottom="@dimen/tpds_all_dp_66" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:back_width="@dimen/tpds_all_dp_16" app:current_progress="0" app:progress_width="@dimen/tpds_all_dp_16" app:progress_color="@color/color_orange"/> <LinearLayout android:layout_width="@dimen/tpds_all_dp_100" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="center" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@+id/progress_view_power" app:layout_constraintBottom_toBottomOf="@+id/progress_view_power"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/tv_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0" android:textColor="@color/color_red" android:textSize="@dimen/tpds_all_text_size_40" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"/> <TextView android:id="@+id/tv_percent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="2dp" android:layout_marginBottom="6dp" android:text="%" android:textColor="@color/color_red" android:textSize="@dimen/tpds_all_text_size_18" app:layout_constraintLeft_toRightOf="@+id/tv_progress" app:layout_constraintBottom_toBottomOf="@id/tv_progress"/> </androidx.constraintlayout.widget.ConstraintLayout> <ImageView android:id="@+id/iv_lighting" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/ic_lighting" android:visibility="gone"/> <TextView android:id="@+id/tv_battery_capacity" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:text="@string/solar_battery_level" android:textSize="@dimen/tpds_all_text_size_12" android:textColor="@color/color_text_third_content" android:maxLines="2" android:visibility="gone"/> </LinearLayout> <androidx.recyclerview.widget.RecyclerView android:id="@+id/solar_bat_status_rv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/tpds_all_dp_16" android:gravity="center" app:layout_constraintTop_toBottomOf="@+id/progress_view_power" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" android:visibility="gone"/> </com.tplink.design.card.TPConstraintCardView> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <!-- 一键布防一键撤防--> <androidx.constraintlayout.widget.Guideline android:id="@+id/guide_line" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_end="205dp" /> <com.tplink.ipc.feature.devicesetting.nvrOverview.view.SlideSwitchWithLoadingStatusView android:id="@+id/cv_arm_disarm_batch" style="@style/setting_tp_constraint_cardview_top_16dp_width_0dp" android:layout_width="188dp" android:layout_height="140dp" android:layout_marginEnd="@dimen/tpds_all_dp_6" app:layout_constraintEnd_toEndOf="@+id/guide_line" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:titleText="@string/nvr_management_center_slide_arming" /> <com.tplink.ipc.feature.devicesetting.nvrOverview.view.SlideSwitchWithLoadingStatusView android:id="@+id/cv_manual_batch_msg_alarm" style="@style/setting_tp_constraint_cardview_top_16dp_width_0dp" app:titleText="@string/nvr_management_center_slide_alarm" android:layout_marginStart="@dimen/tpds_all_dp_6" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@+id/guide_line" app:layout_constraintTop_toTopOf="parent"/> <androidx.constraintlayout.widget.Barrier android:id="@+id/barrier_arm" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="bottom" app:constraint_referenced_ids="cv_arm_disarm_batch,cv_manual_batch_msg_alarm" /> </androidx.constraintlayout.widget.ConstraintLayout> <!--Device Share --> <com.tplink.design.card.TPConstraintCardView android:id="@+id/cv_device_share" style="@style/setting_tp_constraint_cardview_top_16dp"> <RelativeLayout android:id="@+id/rl_setting_device_share" android:layout_width="match_parent" android:layout_height="wrap_content"> <com.tplink.design.list.TPSingleLineItemView android:id="@+id/line1_setting_device_share" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="false" app:itemTitle="@string/setting_device_share" android:layout_alignParentStart="true" android:layout_alignParentEnd="true" android:layout_toStartOf="@+id/setting_device_share_item_right_tv" android:layout_centerVertical="true"/> <ImageView android:id="@+id/setting_device_share_item_right_iv" style="@style/setting_device_share_user_image" android:layout_toStartOf="@+id/setting_device_share_item_right_tv" /> <TextView android:id="@+id/setting_device_share_item_right_tv" style="@style/setting_device_share_user_text" android:layout_toStartOf="@+id/iv_setting_device_share_next" /> <ImageView android:id="@+id/iv_setting_device_share_next" style="@style/setting_item_next_image" android:layout_alignParentEnd="true" /> </RelativeLayout> </com.tplink.design.card.TPConstraintCardView> <com.tplink.design.card.TPConstraintCardView android:id="@+id/cv_device_info" style="@style/setting_tp_constraint_cardview_top_16dp"> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_connection" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="connection" app:layout_constraintTop_toTopOf="parent" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_status" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="@string/solar_device_detail_status" app:layout_constraintTop_toBottomOf="@id/line2_device_connection"/> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_temperature" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/line2_device_status" app:itemTitle="@string/device_nct" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_charging_power" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/line2_device_temperature" app:itemTitle="@string/solar_device_detail_charging_power" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_load_power" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/line2_charging_power" app:itemTitle="@string/solar_device_detail_load_power" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_connected_to_select" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/line2_load_power" app:itemEndIcon="@drawable/ic_arrow_for_popup_window" app:itemTitle="Connected to" > <TextView android:id="@+id/tv_connected_select" android:layout_width="wrap_content" android:layout_height="wrap_content" style="?attr/textAppearanceSubtitle1" android:textColor="@color/color_text_second_content" android:layout_marginEnd="@dimen/tpds_all_dp_8" app:layout_constraintStart_toEndOf="@+id/title" app:layout_constraintEnd_toStartOf ="@+id/end_icon" app:layout_constraintTop_toTopOf="@+id/end_icon"/> </com.tplink.design.list.TPTwoLineItemView> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_model" style="@style/setting_tp_line_item_view" app:itemTitle="@string/setting_about_device_model" app:layout_constraintTop_toBottomOf="@id/line2_connected_to_select" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_setting_firmware_item" style="@style/setting_tp_line_item_view_next" app:itemTitle="@string/setting_firmware_version" app:layout_constraintTop_toBottomOf="@id/line2_device_model"/> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_sn" style="@style/setting_tp_line_item_view" app:itemTitle="sn" app:layout_constraintTop_toBottomOf="@id/line2_setting_firmware_item" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_id" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="@string/device_add_id_input_guide_device_id_hint" app:layout_constraintTop_toBottomOf="@id/line2_device_sn"> <ImageView android:id="@+id/iv_copy_device_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_copy_device_id" android:layout_marginEnd="@dimen/tpds_all_dp_12" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/iv_copy_qr_code"/> <ImageView android:id = "@+id/iv_copy_qr_code" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_copy_qr_code" android:layout_marginEnd="@dimen/tpds_all_dp_12" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"/> </com.tplink.design.list.TPTwoLineItemView> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_ip_address" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="@string/setting_about_recorder_ip_address" app:layout_constraintTop_toBottomOf="@id/line2_device_id" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_mac_address" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="@string/setting_about_recorder_mac_address" app:layout_constraintTop_toBottomOf="@id/line2_device_ip_address" /> <com.tplink.design.list.TPTwoLineItemView style="@style/setting_tp_line_item_view" android:id="@+id/line2_device_resolution" app:itemTitle="Resolution" app:layout_constraintTop_toBottomOf="@id/line2_device_mac_address" /> <com.tplink.design.list.TPTwoLineItemView style="@style/setting_tp_line_item_view" android:id="@+id/line2_device_frame_rate" app:itemTitle="Frame Rate" app:layout_constraintTop_toBottomOf="@id/line2_device_resolution" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_channel_cnt" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="@string/ipc_nvr_channel_name_fix" app:layout_constraintTop_toBottomOf="@id/line2_device_frame_rate" /> <com.tplink.design.list.TPTwoLineItemView android:id="@+id/line2_device_up_time" android:layout_width="match_parent" android:layout_height="wrap_content" app:itemTitle="Up Time" app:layout_constraintTop_toBottomOf="@id/line2_channel_cnt" /> </com.tplink.design.card.TPConstraintCardView> </LinearLayout> 请你根据我的xml文件在ui页面里定义组件名称,并且findviewByid,组件名称以m开头,组件类型结尾
最新发布
01-08
void InputReader::loopOnce() { int32_t oldGeneration; int32_t timeoutMillis; // Copy some state so that we can access it outside the lock later. bool inputDevicesChanged = false; std::vector<InputDeviceInfo> inputDevices; std::list<NotifyArgs> notifyArgs; { // acquire lock std::scoped_lock _l(mLock); oldGeneration = mGeneration; timeoutMillis = -1; auto changes = mConfigurationChangesToRefresh; if (changes.any()) { mConfigurationChangesToRefresh.clear(); timeoutMillis = 0; refreshConfigurationLocked(changes); } else if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); } } // release lock std::vector<RawEvent> events = mEventHub->getEvents(timeoutMillis); { // acquire lock std::scoped_lock _l(mLock); mReaderIsAliveCondition.notify_all(); if (!events.empty()) { mPendingArgs += processEventsLocked(events.data(), events.size()); } if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (now >= mNextTimeout) { if (debugRawEvents()) { ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); } mNextTimeout = LLONG_MAX; mPendingArgs += timeoutExpiredLocked(now); } } if (oldGeneration != mGeneration) { inputDevicesChanged = true; inputDevices = getInputDevicesLocked(); mPendingArgs.emplace_back( NotifyInputDevicesChangedArgs{mContext.getNextId(), inputDevices}); } std::swap(notifyArgs, mPendingArgs); // Keep track of the last used device for (const NotifyArgs& args : notifyArgs) { mLastUsedDeviceId = getDeviceIdOfNewGesture(args).value_or(mLastUsedDeviceId); } } // release lock // Flush queued events out to the listener. // This must happen outside of the lock because the listener could potentially call // back into the InputReader's methods, such as getScanCodeState, or become blocked // on another thread similarly waiting to acquire the InputReader lock thereby // resulting in a deadlock. This situation is actually quite plausible because the // listener is actually the input dispatcher, which calls into the window manager, // which occasionally calls into the input reader. for (const NotifyArgs& args : notifyArgs) { mNextListener.notify(args); } // Notify the policy that input devices have changed. // This must be done after flushing events down the listener chain to ensure that the rest of // the listeners are synchronized with the changes before the policy reacts to them. if (inputDevicesChanged) { mPolicy->notifyInputDevicesChanged(inputDevices); } // Notify the policy of configuration change. This must be after policy is notified about input // device changes so that policy can fetch newly added input devices on configuration change. for (const auto& args : notifyArgs) { const auto* configArgs = std::get_if<NotifyConfigurationChangedArgs>(&args); if (configArgs != nullptr) { mPolicy->notifyConfigurationChanged(configArgs->eventTime); } } // Notify the policy of the start of every new stylus gesture. for (const auto& args : notifyArgs) { const auto* motionArgs = std::get_if<NotifyMotionArgs>(&args); if (motionArgs != nullptr && isStylusPointerGestureStart(*motionArgs)) { mPolicy->notifyStylusGestureStarted(motionArgs->deviceId, motionArgs->eventTime); } } } std::list<NotifyArgs> InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { std::list<NotifyArgs> out; for (const RawEvent* rawEvent = rawEvents; count;) { int32_t type = rawEvent->type; size_t batchSize = 1; if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { int32_t deviceId = rawEvent->deviceId; while (batchSize < count) { if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || rawEvent[batchSize].deviceId != deviceId) { break; } batchSize += 1; } if (debugRawEvents()) { ALOGD("BatchSize: %zu Count: %zu", batchSize, count); } out += processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::DEVICE_REMOVED: removeDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); break; default: ALOG_ASSERT(false); // can't happen break; } } count -= batchSize; rawEvent += batchSize; } return out; } std::list<NotifyArgs> InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, size_t count) { auto deviceIt = mDevices.find(eventHubId); if (deviceIt == mDevices.end()) { ALOGW("Discarding event for unknown eventHubId %d.", eventHubId); return {}; } std::shared_ptr<InputDevice>& device = deviceIt->second; if (device->isIgnored()) { // ALOGD("Discarding event for ignored deviceId %d.", deviceId); return {}; } //#ifdef OPLUS_EXTENSION_HOOK //yang.y.liu@Game.Joystick, 2021/07/14, Add for joystick adapter if (!getInputFlingerExt()->processEventsForDeviceLocked(device.get(), eventHubId, rawEvents, count)) { ALOGV("game code processEventsForDeviceLocked return {}"); return {}; } //#endif return device->process(rawEvents, count); } std::list<NotifyArgs> InputDevice::process(const RawEvent* rawEvents, size_t count) { // Process all of the events in order for each mapper. // We cannot simply ask each mapper to process them in bulk because mappers may // have side-effects that must be interleaved. For example, joystick movement events and // gamepad button presses are handled by different mappers but they should be dispatched // in the order received. std::list<NotifyArgs> out; for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) { if (debugRawEvents()) { const auto [type, code, value] = InputEventLookup::getLinuxEvdevLabel(rawEvent->type, rawEvent->code, rawEvent->value); ALOGD("Input event: eventHubDevice=%d type=%s code=%s value=%s when=%" PRId64, rawEvent->deviceId, type.c_str(), code.c_str(), value.c_str(), rawEvent->when); } if (mDropUntilNextSync) { if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { out += reset(rawEvent->when); mDropUntilNextSync = false; ALOGD_IF(debugRawEvents(), "Recovered from input event buffer overrun."); } else { ALOGD_IF(debugRawEvents(), "Dropped input event while waiting for next input sync."); } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { ALOGI("Detected input event buffer overrun for device %s.", getName().c_str()); mDropUntilNextSync = true; } else { for_each_mapper_in_subdevice(rawEvent->deviceId, [&](InputMapper& mapper) { out += mapper.process(*rawEvent); }); } --count; } postProcess(out); return out; } std::list<NotifyArgs> KeyboardInputMapper::process(const RawEvent& rawEvent) { std::list<NotifyArgs> out; mHidUsageAccumulator.process(rawEvent); switch (rawEvent.type) { //#ifdef OPLUS_FEATURE_INPUT // Xingxing.Guo@ANDROID.INPUT, 7251550, 2024/06/06, add for spruce. case EV_KEY: { int32_t scanCode = rawEvent.code; SpruceSwipEnable = false; if ((scanCode == SPRUCE_SWIP_DOWN_SCAN_CODE || scanCode == SPRUCE_SWIP_UP_SCAN_CODE) && (rawEvent.value != 0)) { SpruceSwipEnable = true; SpruceScanCode = scanCode; } else if (isSupportedScanCode(scanCode)) { out += processKey(rawEvent.when, rawEvent.readTime, rawEvent.value != 0, scanCode, mHidUsageAccumulator.consumeCurrentHidUsage()); } break; } case EV_ABS: { if (SpruceSwipEnable) { ALOGI("EV_ABS ScanCode=0x%04x SpruceSwipValue=0x%08x", SpruceScanCode, rawEvent.value); SpruceSwipValue = rawEvent.value; out += processKey(rawEvent.when, rawEvent.readTime, true, SpruceScanCode, mHidUsageAccumulator.consumeCurrentHidUsage()); SpruceSwipEnable = false; } break; } default: { SpruceSwipEnable = false; break; } //#else /* case EV_KEY: { int32_t scanCode = rawEvent.code; if (isSupportedScanCode(scanCode)) { out += processKey(rawEvent.when, rawEvent.readTime, rawEvent.value != 0, scanCode, mHidUsageAccumulator.consumeCurrentHidUsage()); } } */ //#endif OPLUS_FEATURE_INPUT */ } return out; } std::list<NotifyArgs> KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down, int32_t scanCode, int32_t usageCode) { std::list<NotifyArgs> out; int32_t keyCode; int32_t keyMetaState; uint32_t policyFlags; int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM; if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState, &policyFlags)) { keyCode = AKEYCODE_UNKNOWN; keyMetaState = mMetaState; policyFlags = 0; } nsecs_t downTime = when; std::optional<size_t> keyDownIndex = findKeyDownIndex(scanCode); //#ifdef OPLUS_FEATURE_ROTATE_VOLUMEKEY //Xiaobo.Ding@ANDROID.Input 2022/09/09, Add for ROTATE_VOLUMEKEY if (mSupportRotateVolume) { keyCode = rotateVolumeKeyCode(keyCode, down); } //endif /* OPLUS_FEATURE_ROTATE_VOLUMEKEY */ if (down) { // Rotate key codes according to orientation if needed. if (mParameters.orientationAware) { keyCode = rotateKeyCode(keyCode, getOrientation()); } // Add key down. if (keyDownIndex) { // key repeat, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns[*keyDownIndex].keyCode; downTime = mKeyDowns[*keyDownIndex].downTime; flags = mKeyDowns[*keyDownIndex].flags; } else { // key down if ((policyFlags & POLICY_FLAG_VIRTUAL) && getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) { return out; } if (policyFlags & POLICY_FLAG_GESTURE) { out += getDeviceContext().cancelTouch(when, readTime); flags |= AKEY_EVENT_FLAG_KEEP_TOUCH_MODE; } KeyDown keyDown; keyDown.keyCode = keyCode; keyDown.scanCode = scanCode; keyDown.downTime = when; keyDown.flags = flags; mKeyDowns.push_back(keyDown); } onKeyDownProcessed(downTime); } else { // Remove key down. if (keyDownIndex) { // key up, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns[*keyDownIndex].keyCode; downTime = mKeyDowns[*keyDownIndex].downTime; flags = mKeyDowns[*keyDownIndex].flags; mKeyDowns.erase(mKeyDowns.begin() + *keyDownIndex); } else { // key was not actually down ALOGI("Dropping key up from device %s because the key was not down. " "keyCode=%d, scanCode=%d", getDeviceName().c_str(), keyCode, scanCode); return out; } } if (updateMetaStateIfNeeded(keyCode, down)) { // If global meta state changed send it along with the key. // If it has not changed then we'll use what keymap gave us, // since key replacement logic might temporarily reset a few // meta bits for given key. keyMetaState = mMetaState; } DeviceId deviceId = getDeviceId(); // On first down: Process key for keyboard classification (will send reconfiguration if the // keyboard type change) if (down && !keyDownIndex) { KeyboardClassifier& classifier = getDeviceContext().getContext()->getKeyboardClassifier(); classifier.processKey(deviceId, scanCode, keyMetaState); getDeviceContext().setKeyboardType(classifier.getKeyboardType(deviceId)); } KeyboardType keyboardType = getDeviceContext().getKeyboardType(); // Any key down on an external keyboard should wake the device. // We don't do this for internal keyboards to prevent them from waking up in your pocket. // For internal keyboards and devices for which the default wake behavior is explicitly // prevented (e.g. TV remotes), the key layout file should specify the policy flags for each // wake key individually. if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault && !(keyboardType != KeyboardType::ALPHABETIC && isMediaKey(keyCode))) { policyFlags |= POLICY_FLAG_WAKE; } //#ifndef OPLUS_FEATURE_INPUT_LASER //Xingxing.Guo@ANDROID.6722667, 2024/03/04, add for pad laser if (getDeviceContext().isLaserPencilDevice()) { ALOGD("Laser from device %s " "keyCode=%d, scanCode=%d", getDeviceName().c_str(), keyCode, scanCode); if (!mKeyboardConfig.oplusConfigParameters.laserEnabled) { ALOGV("Laser is not supported!"); return out; } else if (policyFlags & POLICY_FLAG_WAKE) { policyFlags &= ~POLICY_FLAG_WAKE; } } //#endif /* OPLUS_FEATURE_INPUT_LASER */ if (mParameters.handlesKeyRepeat) { policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; } //#ifdef OPLUS_FEATURE_INPUT // Xingxing.Guo@ANDROID.INPUT, 7251550, 2024/06/06, add for spruce. if (SpruceSwipEnable) { SpruceSwipEnable = false; when = SpruceSwipValue; } //#endif OPLUS_FEATURE_INPUT */ out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when, readTime, deviceId, mSource, getDisplayId(), policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, flags, keyCode, scanCode, keyMetaState, downTime)); //#ifdef OPLUS_EXTENSION_DEBUG //luochuang@ANDROID.INPUT, 2021/05/25, saupwkProcessKey feature extern void __attribute__((weak)) saupwkProcessKey(int32_t scanCode, bool down); if(saupwkProcessKey) { ALOGV("theia start saupwkProcessKey"); saupwkProcessKey(scanCode, down); } //#endif /* OPLUS_EXTENSION_DEBUG */ return out; } 这几段代码是获取按键亮屏中的部分,请告诉我每一个函数在其中的作用以及关键代码解释,在 KeyboardInputMapper::processKey最后的out返回到inputreader之后又要怎么执行,请基于安卓15源码正确详细讲解
09-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值