GVKun编程网logo

android camera setDisplayOrientation(90)在不同的设备中失败(the android camera encountered)

30

最近很多小伙伴都在问androidcamerasetDisplayOrientation(90)在不同的设备中失败和theandroidcameraencountered这两个问题,那么本篇文章就来给

最近很多小伙伴都在问android camera setDisplayOrientation(90)在不同的设备中失败the android camera encountered这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展(OK) Android graphic (12)—display 上层相关概念、关系 - mLogicalDisplays.get (Display.DEFAULT_DISPLAY)、:java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams cannot be cast to androi...、Android 4.4 (KitKat) 上的 Android Gallery 为 Intent.ACTION_GET_CONTENT 返回不同的 URI、Android Camera Orientation ISsue等相关知识,下面开始了哦!

本文目录一览:

android camera setDisplayOrientation(90)在不同的设备中失败(the android camera encountered)

android camera setDisplayOrientation(90)在不同的设备中失败(the android camera encountered)

我的相机应用程序有问题.相机活动处于纵向模式.所以我给了
camera.setdisplayOrientation(90);

根据SO中的不同帖子,这将在纵向模式下正常工作.

但它不能正常使用不同的设备.问题是,预览向左或向右旋转90度.在Htc中没关系.但是对于galaxy系列,它不起作用.

谁能帮我 ?

解决方法

我把这个 answer给了一个类似的问题,但正如你所说它是在HTC设备上.我建议您在旋转代码中添加断点并在物理旋转设备时检查变量 – 这可能有助于识别与galaxy模型不同的情况.

(OK) Android graphic (12)—display 上层相关概念、关系 - mLogicalDisplays.get (Display.DEFAULT_DISPLAY)

(OK) Android graphic (12)—display 上层相关概念、关系 - mLogicalDisplays.get (Display.DEFAULT_DISPLAY)


http://blog.csdn.net/lewif/article/details/50827430


涉及的 java 类

DisplayManagerService

Manages attached displays.
The DisplayManagerService manages the global lifecycle of displays,
decides how to configure logical displays based on the physical display devices currently
attached, sends notifications to the system and to applications when the state
changes, and so on.
The display manager service relies on a collection of DisplayAdapter components,
for discovering and configuring physical display devices attached to the system.
There are separate display adapters for each manner that devices are attached:
one display adapter for built-in local displays, one for simulated non-functional
displays when the system is headless, one for simulated overlay displays used for
development, one for wifi displays, etc.
Display adapters are only weakly coupled to the display manager service.
Display adapters communicate changes in display device state to the display manager
service asynchronously via a DisplayAdapter.Listener registered
by the display manager service.  This separation of concerns is important for
two main reasons.  First, it neatly encapsulates the responsibilities of these
two classes: display adapters handle individual display devices whereas
the display manager service handles the global state.  Second, it eliminates
the potential for deadlocks resulting from asynchronous display device discovery.

DisplayAdapter

A display adapter makes zero or more display devices available to the system
and provides facilities for discovering when displays are connected or disconnected.
For now, all display adapters are registered in the system server but
in principle it could be done from other processes.

现在支持的 4 种 Adapter,分别对应不同类型的 display。

1.LocalDisplayAdapter
A display adapter for the local displays managed by Surface Flinger
2.WifiDisplayAdapter
Connects to Wifi displays that implement the Miracast protocol.
This class is responsible for connecting to Wifi displays and mediating
the interactions between Media Server, Surface Flinger and the Display Manager Service.
3.VirtualDisplayAdapter
4.OverlayDisplayAdapter

DisplayDevice

 Represents a physical display device such as the built-in display an external monitor, or a WiFi display.
WifiDisplayDevice
VirtualDisplayDevice
OverlayDisplayDevice
LocalDisplayDevice

DisplayManagerGlobal

Manager communication with the display manager service on behalf of an application process.

DisplayManager

Manages the properties of attached displays.

LogicalDisplay

Describes how a logical display is configured.
At this time, we only support logical displays that are coupled to a particular
primary display device from which the logical display derives its basic properties
such as its size, density and refresh rate.
A logical display may be mirrored onto multiple display devices in addition to its
primary display device.  Note that the contents of a logical display may not
always be visible, even on its primary display device, such as in the case where
the primary display device is currently mirroring content from a different
logical display.
Note: The display manager architecture does not actually require logical displays
to be associated with any individual display device.  Logical displays and
display devices are orthogonal concepts.  Some mapping will exist between
logical displays and display devices but it can be many-to-many and
and some might have no relation at all.

Display

Provides information about the size and density of a logical display.

DisplayContent

Utility class for keeping track of the WindowStates and other pertinent contents of a particular Display.

DisplayInfo

Describes the characteristics of a particular logical display.

类之间的关系

以添加系统 built in display 为例,下面是各个类之间的关系图,

这里写图片描述

其中,LocalDisplayDevice 中的 mPhys 是向 surface flinger 获取的 display 的硬件相关属性,而 mDisplayToken 是 surfacefinger 中为 display 创建的 new BBinder 对应的代理对象。

默认屏幕的上层初始化分析

1.
systemserver.Java

/*--------------systemserver.java---------------------------*/
    // 专门为window manager创建了一个handler thread
    // Create a handler thread just for the window manager to enjoy.
        HandlerThread wmHandlerThread = new HandlerThread("WindowManager");
        wmHandlerThread.start();
        //创建一个window manager的Handler(looper是wmHandlerThread线程的)
        Handler wmHandler = new Handler(wmHandlerThread.getLooper());
        wmHandler.post(new Runnable() {
            @Override
            public void run() {
                //Looper.myLooper().setMessageLogging(new LogPrinter(
                //        android.util.Log.DEBUG, TAG, android.util.Log.LOG_ID_SYSTEM));
                android.os.Process.setThreadPriority(
                        android.os.Process.THREAD_PRIORITY_DISPLAY);
                android.os.Process.setCanSelfBackground(false);

                // For debug builds, log event loop stalls to dropbox for analysis.
                if (StrictMode.conditionallyEnableDebugLogging()) {
                    Slog.i(TAG, "Enabled StrictMode logging for WM Looper");
                }
            }
        });
/*--------------systemserver.java---------------------------*/
    // DisplayManagerService display = null;
    // 新建DisplayManagerService服务
        Slog.i(TAG, "Display Manager");
            display = new DisplayManagerService(context, wmHandler);
            ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);
         //需要等待第一个display初始化完成后,才继续进行,否则一直循环
        if (!display.waitForDefaultDisplay()) {
                reportWtf("Timeout waiting for default display to be initialized.",
                        new Throwable());
            }
/*--------------DisplayManagerService.java---------------------------*/
    // 在mSyncRoot wait,直到mLogicalDisplays.get(Display.DEFAULT_DISPLAY)不为null
    // 即有地方添加了默认display的LogicalDisplay
    /**
     * Pauses the boot process to wait for the first display to be initialized.
     */
    public boolean waitForDefaultDisplay() {
        synchronized (mSyncRoot) {
            long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
            while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
                long delay = timeout - SystemClock.uptimeMillis();
                if (delay <= 0) {
                    return false;
                }
                if (DEBUG) {
                    Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
                }
                try {
                    mSyncRoot.wait(delay);
                } catch (InterruptedException ex) {
                }
            }
        }
        return true;
    }
/*--------------DisplayManagerService.java---------------------------*/
   public DisplayManagerService(Context context, Handler mainHandler) {
        mContext = context;
        mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
    //新建个DisplayManagerHandler
        mHandler = new DisplayManagerHandler(mainHandler.getLooper());
        mUiHandler = UiThread.getHandler();
        //新建个DisplayAdapterListener
        mDisplayAdapterListener = new DisplayAdapterListener();
        //persist.demo.singledisplay是只创建默认display的logical display
        mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);

        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
    }

DisplayManagerHandler 的消息处理函数,

/*--------------DisplayManagerService.java---------------------------*/
private final class DisplayManagerHandler extends Handler {
        public DisplayManagerHandler(Looper looper) {
            super(looper, null, true /*async*/);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
                    registerDefaultDisplayAdapter();
                    break;

                case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
                    registerAdditionalDisplayAdapters();
                    break;

                case MSG_DELIVER_DISPLAY_EVENT:
                    deliverDisplayEvent(msg.arg1, msg.arg2);
                    break;

                case MSG_REQUEST_TRAVERSAL:
                    mWindowManagerFuncs.requestTraversal();
                    break;

                case MSG_UPDATE_VIEWPORT: {
                    synchronized (mSyncRoot) {
                        mTempDefaultViewport.copyFrom(mDefaultViewport);
                        mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
                    }
                    mInputManagerFuncs.setDisplayViewports(
                            mTempDefaultViewport, mTempExternalTouchViewport);
                    break;
                }
            }
        }
    }

DisplayAdapterListener 类,

/*--------------DisplayManagerService.java---------------------------*/
    private final class DisplayAdapterListener implements DisplayAdapter.Listener {
        @Override
        public void onDisplayDeviceEvent(DisplayDevice device, int event) {
            switch (event) {
                case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
                    handleDisplayDeviceAdded(device);
                    break;

                case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
                    handleDisplayDeviceChanged(device);
                    break;

                case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
                    handleDisplayDeviceRemoved(device);
                    break;
            }
        }

        @Override
        public void onTraversalRequested() {
            synchronized (mSyncRoot) {
                scheduleTraversalLocked(false);
            }
        }
    }
mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
/* ro.config.headless
    系统中判断ro.config.headless的总共有几个地方
    a、SurfaceControl.java在构造函数中判断如果是headless设备则抛出异常,说明headless的设备不应该构造任何显示画面
    b、在SystemUI中判断headless为true的情况下不启动WallpaperManagerService和SystemUIService
    c、在PhoneWindowManager的systemReady中判断headless为true的情况下不起动KeyguardServiceDelegate,不显示启动提示消息,屏蔽滑盖(lid)状态,屏蔽一些按键
    d、DisplayManagerService在创建默认显示设备的时候(registerDefaultDisplayAdapter)判断headless为true的情况下创建的是HeadlessDisplayAdapter而非LocalDisplayAdapter,前者并没有通过SurfaceFlinger.getBuiltInDisplay获取一个对应的DisplayDevice,也就是说上层的默认显示设备是空
    e、ActivityManagerService在startHomeActivityLocked断headless为true的情况下不启动HomeActivity,不能启动Activity,不能重启挂掉的进程(即使是persistent),不能更新屏幕配置。
*/

mHandler 的 MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER 处理函数为,

/*--------------DisplayManagerService.java---------------------------*/
    private void registerDefaultDisplayAdapter() {
        // Register default display adapter.
        synchronized (mSyncRoot) {
            if (mHeadless) {
                registerDisplayAdapterLocked(new HeadlessDisplayAdapter(
                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
            } else {
                //走这个分支
                registerDisplayAdapterLocked(new LocalDisplayAdapter(
                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
            }
        }
    }

LocalDisplayAdapter 构造函数的 mHandler 和 mDisplayAdapterListener 分别为 DisplayManagerHandler 和 DisplayAdapterListener。

/*--------------LocalDisplayAdapter.java---------------------------*/
    /* class LocalDisplayAdapter extends DisplayAdapter */
    // Called with SyncRoot lock held.
    public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
            Context context, Handler handler, Listener listener) {
        super(syncRoot, context, handler, listener, TAG);
    }
    /*--------------DisplayAdapter.java---------------------------*/
   // LocalDisplayAdapter是 DisplayAdapter的子类
   public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
            Context context, Handler handler, Listener listener, String name) {
        mSyncRoot = syncRoot;
        mContext = context;
        mHandler = handler;
        mListener = listener;
        mName = name;
    }
/*--------------DisplayManagerService.java---------------------------*/
//    private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
        private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
        mDisplayAdapters.add(adapter);
        adapter.registerLocked();
    }

LocalDisplayAdapter.registerLocked(),

/*--------------LocalDisplayAdapter.java---------------------------*/       
        private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
            SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
            SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
    };

    // LocalDisplayAdapter.registerLocked
        public void registerLocked() {
        super.registerLocked();

        mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
    //对默认屏幕和HDMI调用tryConnectDisplayLocked
        for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
            tryConnectDisplayLocked(builtInDisplayId);
        }
    }

调用 tryConnectDisplayLocked (),这里主要是和底层 framework 去交互,获取底层注册的 displays 的相关信息。

/*--------------LocalDisplayAdapter.java---------------------------*/ 
      // LocalDisplayAdapter.mDevices 
      // private final SparseArray<LocalDisplayDevice> mDevices =new SparseArray<LocalDisplayDevice>();
      private void tryConnectDisplayLocked(int builtInDisplayId) {
      //获取surface flinger中的new BBinder对应的client IBinder
        IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
        //获取display的硬件属性,新建LocalDisplayDevice
        if (displayToken != null && SurfaceControl.getDisplayInfo(displayToken, mTempPhys)) {
            LocalDisplayDevice device = mDevices.get(builtInDisplayId);
            if (device == null) {
                // Display was added.
                device = new LocalDisplayDevice(displayToken, builtInDisplayId, mTempPhys);
                mDevices.put(builtInDisplayId, device);
                //给DisplayManagerService的DisplayManagerHandler发消息
                sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
            } else if (device.updatePhysicalDisplayInfoLocked(mTempPhys)) {
                // Display properties changed.
                sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
            }
        } else {
            // The display is no longer available. Ignore the attempt to add it.
            // If it was connected but has already been disconnected, we''ll get a
            // disconnect event that will remove it from mDevices.
        }
    }
/*--------------SurfaceControl.java---------------------------*/
    //SurfaceControl.java,都是static,类函数
    //通过id获取display token
    public static IBinder getBuiltInDisplay(int builtInDisplayId) {
        return nativeGetBuiltInDisplay(builtInDisplayId);
    }
        //通过display token,获取display硬件属性
        public static boolean getDisplayInfo(IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo) {
        if (displayToken == null) {
            throw new IllegalArgumentException("displayToken must not be null");
        }
        if (outInfo == null) {
            throw new IllegalArgumentException("outInfo must not be null");
        }
        return nativeGetDisplayInfo(displayToken, outInfo);
    }

其中,nativeGetBuiltInDisplay 最终会调用 surfaceflinger 中的 getBuiltInDisplay,通过 Binder 传回代理对象。

/*--------------SurfaceFlinger.cpp---------------------------*/
sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
    if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
        ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
        return NULL;
    }
    return mBuiltinDisplays[id];
}

nativeGetDisplayInfo—>SurfaceFlinger::getDisplayInfo,

/*--------------SurfaceFlinger.cpp---------------------------*/
status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
    int32_t type = NAME_NOT_FOUND;
    for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
        if (display == mBuiltinDisplays[i]) {
            type = i;
            break;
        }
    }

    if (type < 0) {
        return type;
    }

    const HWComposer& hwc(getHwComposer());
    float xdpi = hwc.getDpiX(type);
    float ydpi = hwc.getDpiY(type);

    // TODO: Not sure if display density should handled by SF any longer
    class Density {
        static int getDensityFromProperty(char const* propName) {
            char property[PROPERTY_VALUE_MAX];
            int density = 0;
            if (property_get(propName, property, NULL) > 0) {
                density = atoi(property);
            }
            return density;
        }
    public:
        static int getEmuDensity() {
            return getDensityFromProperty("qemu.sf.lcd_density"); }
        static int getBuildDensity()  {
            return getDensityFromProperty("ro.sf.lcd_density"); }
    };

    if (type == DisplayDevice::DISPLAY_PRIMARY) {
        // The density of the device is provided by a build property
        float density = Density::getBuildDensity() / 160.0f;
        if (density == 0) {
            // the build doesn''t provide a density -- this is wrong!
            // use xdpi instead
            ALOGE("ro.sf.lcd_density must be defined as a build property");
            density = xdpi / 160.0f;
        }
        if (Density::getEmuDensity()) {
            // if "qemu.sf.lcd_density" is specified, it overrides everything
            xdpi = ydpi = density = Density::getEmuDensity();
            density /= 160.0f;
        }
        info->density = density;

        // TODO: this needs to go away (currently needed only by webkit)
        sp<const DisplayDevice> hw(getDefaultDisplayDevice());
        info->orientation = hw->getOrientation();
    } else {
        // TODO: where should this value come from?
        static const int TV_DENSITY = 213;
        info->density = TV_DENSITY / 160.0f;
        info->orientation = 0;
    }

    info->w = hwc.getWidth(type);
    info->h = hwc.getHeight(type);
    info->xdpi = xdpi;
    info->ydpi = ydpi;
    info->fps = float(1e9 / hwc.getRefreshPeriod(type));

    // All non-virtual displays are currently considered secure.
    info->secure = true;

    return NO_ERROR;
}

创建完 LocalDisplayDevice,给 DisplayManagerService 的 DisplayManagerHandler 发消息,

/*--------------DisplayAdapter.java---------------------------*/
    /**
     * Sends a display device event to the display adapter listener asynchronously.
     */
    protected final void sendDisplayDeviceEventLocked(
            final DisplayDevice device, final int event) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mListener.onDisplayDeviceEvent(device, event);
            }
        });
    }

LocalDisplayAdapter 构造函数的 mHandler 和 mDisplayAdapterListener 分别为 DisplayManagerHandler 和 DisplayAdapterListener,进而会去调用,

/*--------------DisplayManagerService.java---------------------------*/
        private void handleDisplayDeviceAdded(DisplayDevice device) {
        synchronized (mSyncRoot) {
            handleDisplayDeviceAddedLocked(device);
        }
    }
/*--------------DisplayManagerService.java---------------------------*/
    //输入为LocalDisplayDevice
    //    private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>();
    private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
        if (mDisplayDevices.contains(device)) {
            Slog.w(TAG, "Attempted to add already added display device: "
                    + device.getDisplayDeviceInfoLocked());
            return;
        }

        Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
    // List of all currently connected display devices.
    //将LocalDisplayDevice添加到mDisplayDevices
        mDisplayDevices.add(device);
        //为一个物理display添加一个logical display
        addLogicalDisplayLocked(device);
        updateDisplayBlankingLocked(device);
        scheduleTraversalLocked(false);
    }

为物理屏幕创建一个 logical display,

/*--------------DisplayManagerService.java---------------------------*/
// Adds a new logical display based on the given display device.
    // Sends notifications if needed.
    private void addLogicalDisplayLocked(DisplayDevice device) {
        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
        boolean isDefault = (deviceInfo.flags
                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
        //主屏,同时mLogicalDisplays包含了这个device
        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
            Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
            isDefault = false;
        }
        //不是主屏,但是mSingleDisplayDemoMode为真,即设置了单屏模式
        //这时候不会去为这个物理display创建新的logical display,如果
        //有hdmi,这时候会mirror主屏的内容
        //看来逻辑display就是和显示的内容有很大的关系
        if (!isDefault && mSingleDisplayDemoMode) {
            Slog.i(TAG, "Not creating a logical display for a secondary display "
                    + " because single display demo mode is enabled: " + deviceInfo);
            return;
        }

        final int displayId = assignDisplayIdLocked(isDefault);
        // layerStack 就是displayId id,主屏0,hdmi 1
        final int layerStack = assignLayerStackLocked(displayId);

        //新建LogicalDisplay
        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
        display.updateLocked(mDisplayDevices);
        if (!display.isValidLocked()) {
            // This should never happen currently.
            Slog.w(TAG, "Ignoring display device because the logical display "
                    + "created from it was not considered valid: " + deviceInfo);
            return;
        }

        mLogicalDisplays.put(displayId, display);

        //如果添加的是built-in display,需要mSyncRoot.notifyAll()
        //因为systemserver.java中调用了waitForDefaultDisplay,这时候systemserver可以继续运行了
        // Wake up waitForDefaultDisplay.
        if (isDefault) {
            mSyncRoot.notifyAll();
        }
    //给mHandler发消息去处理
        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
    }
/*--------------LogicalDisplay.java---------------------------*/
    public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
        mDisplayId = displayId;
        mLayerStack = layerStack;
        mPrimaryDisplayDevice = primaryDisplayDevice;
    }

进而去调用 mHandler 的 deliverDisplayEvent,先不去管 mCallbacks 是在哪里注册的,进而会去调用 mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);

/*--------------DisplayManagerService.java---------------------------*/
   private void deliverDisplayEvent(int displayId, int event) {
        if (DEBUG) {
            Slog.d(TAG, "Delivering display event: displayId="
                    + displayId + ", event=" + event);
        }

        // Grab the lock and copy the callbacks.
        final int count;
        synchronized (mSyncRoot) {
        //这里的mCallbacks是哪里注册的??
            count = mCallbacks.size();
            mTempCallbacks.clear();
            for (int i = 0; i < count; i++) {
                mTempCallbacks.add(mCallbacks.valueAt(i));
            }
        }

        // After releasing the lock, send the notifications out.
        for (int i = 0; i < count; i++) {
            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
        }
        mTempCallbacks.clear();
    }

2. mCallbacks 的由来, 上面在添加了默认 display 的 LogicalDisplay 后,会去调用下面代码,使得 systemserver.java 从 waitForDefaultDisplay () 中返回。

/*--------------systemserver.java---------------------------*/
        if (isDefault) {
            mSyncRoot.notifyAll();
        }

进而,systemserver.java 的 initAndLoop () 会去注册 WindowManagerService,

/*--------------systemserver.java---------------------------*/
            wm = WindowManagerService.main(context, power, display, inputManager,
                    wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
                    !firstBoot, onlyCore);

下面分析下,WindowManagerService 的构造函数中做了什么和 display 相关的,

/*--------------WindowManagerService.java---------------------------*/
/*
class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
                DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener
*/
    //WindowManagerService实现了DisplayManager.DisplayListener接口

    private WindowManagerService(Context context, PowerManagerService pm,
            DisplayManagerService displayManager, InputManagerService inputManager,
            boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {

    mDisplayManagerService = displayManager;
    //新建个DisplayManager
    mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
    //由于WindowManagerService实现了DisplayManager.DisplayListener接口,
    //将WindowManagerService注册到DisplayManager中
    mDisplayManager.registerDisplayListener(this, null);    

    }
/*--------------DisplayManager.java---------------------------*/
        public DisplayManager(Context context) {
        mContext = context;
        mGlobal = DisplayManagerGlobal.getInstance();
    }
/*--------------DisplayManagerGlobal.java---------------------------*/

// class DisplayManagerService extends IDisplayManager.Stub 
   public static DisplayManagerGlobal getInstance() {
        synchronized (DisplayManagerGlobal.class) {
            if (sInstance == null) {
                IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
                if (b != null) {
                //输入参数是DisplayManagerService 的代理
                    sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
                }
            }
            return sInstance;
        }
    }

public final class DisplayManagerGlobal {

    //mDm是DisplayManagerService 的代理,用来和DisplayManagerService打交道
    private final IDisplayManager mDm;

        private DisplayManagerGlobal(IDisplayManager dm) {
        mDm = dm;
    }

}

接着将 WindowManagerService 注册到 DisplayManager 中,

/*--------------DisplayManager.java---------------------------*/
        //输入参数为WindowManagerService,null    
        public void registerDisplayListener(DisplayListener listener, Handler handler) {
        mGlobal.registerDisplayListener(listener, handler);
    }
/*--------------DisplayManagerGlobal.java---------------------------*/
        // DisplayManagerGlobal 
        public void registerDisplayListener(DisplayListener listener, Handler handler) {
        if (listener == null) {
            throw new IllegalArgumentException("listener must not be null");
        }
   // private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
    //        new ArrayList<DisplayListenerDelegate>();
        synchronized (mLock) {
            int index = findDisplayListenerLocked(listener);
            if (index < 0) {
             //新建一个display listener的代理者
                mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
             //将DisplayManagerGlobal 和DisplayManagerService 联系起来
            registerCallbackIfNeededLocked();
            }
        }
    }

 public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
            super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
            mListener = listener;
        }
/*--------------DisplayManagerGlobal.java---------------------------*/
// 将    DisplayManagerGlobal 和DisplayManagerService 联系起来
        private void registerCallbackIfNeededLocked() {
        if (mCallback == null) {
            mCallback = new DisplayManagerCallback();
            try {
                //调用DisplayManagerService 的registerCallback将
                //DisplayManagerGlobal 中的DisplayManagerCallback注册到DisplayManagerService中
                mDm.registerCallback(mCallback);
            } catch (RemoteException ex) {
                Log.e(TAG, "Failed to register callback with display manager service.", ex);
                mCallback = null;
            }
        }
    }   
private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
        @Override
        public void onDisplayEvent(int displayId, int event) {
            if (DEBUG) {
                Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
            }
            handleDisplayEvent(displayId, event);
        }
    }

DisplayManagerService 中调用 registerCallback,将 DisplayManagerCallback 保存到 mCallbacks 中,

/*--------------DisplayManagerService.java---------------------------*/
  @Override // Binder call
    public void registerCallback(IDisplayManagerCallback callback) {
        if (callback == null) {
            throw new IllegalArgumentException("listener must not be null");
        }

        synchronized (mSyncRoot) {
            int callingPid = Binder.getCallingPid();
            if (mCallbacks.get(callingPid) != null) {
                throw new SecurityException("The calling process has already "
                        + "registered an IDisplayManagerCallback.");
            }

            CallbackRecord record = new CallbackRecord(callingPid, callback);
            try {
                IBinder binder = callback.asBinder();
                binder.linkToDeath(record, 0);
            } catch (RemoteException ex) {
                // give up
                throw new RuntimeException(ex);
            }
        //保存的是CallbackRecord 
            mCallbacks.put(callingPid, record);
        }
    }
/*--------------DisplayManagerService.java---------------------------*/
    private final class CallbackRecord implements DeathRecipient {
        public final int mPid;
        private final IDisplayManagerCallback mCallback;

        public boolean mWifiDisplayScanRequested;

        public CallbackRecord(int pid, IDisplayManagerCallback callback) {
            mPid = pid;
            mCallback = callback;
        }

        @Override
        public void binderDied() {
            if (DEBUG) {
                Slog.d(TAG, "Display listener for pid " + mPid + " died.");
            }
            onCallbackDied(this);
        }

        public void notifyDisplayEventAsync(int displayId, int event) {
            try {
                mCallback.onDisplayEvent(displayId, event);
            } catch (RemoteException ex) {
                Slog.w(TAG, "Failed to notify process "
                        + mPid + " that displays changed, assuming it died.", ex);
                binderDied();
            }
        }
    }

3. 回到最开始的 deliverDisplayEvent 函数,会调用 CallbackRecord 的 notifyDisplayEventAsync (displayId, event),进而 mCallback.onDisplayEvent(displayId, event),进而调用 DisplayManagerGlobal 的 handleDisplayEvent(displayId, event)

/*--------------DisplayManagerService.java---------------------------*/
 private void deliverDisplayEvent(int displayId, int event) {
        if (DEBUG) {
            Slog.d(TAG, "Delivering display event: displayId="
                    + displayId + ", event=" + event);
        }

        // Grab the lock and copy the callbacks.
        final int count;
        synchronized (mSyncRoot) {
        //这里的mCallbacks是哪里注册的??
            count = mCallbacks.size();
            mTempCallbacks.clear();
            for (int i = 0; i < count; i++) {
                mTempCallbacks.add(mCallbacks.valueAt(i));
            }
        }

        // After releasing the lock, send the notifications out.
        for (int i = 0; i < count; i++) {
            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
        }
        mTempCallbacks.clear();
    }

handleDisplayEvent 中的 mDisplayListeners 就是前面注册的 DisplayListenerDelegate,其中的 listener 和 handler 分别为 WindowManagerService 和 null,


/*--------------DisplayManagerGlobal.java---------------------------*/
    private void handleDisplayEvent(int displayId, int event) {
        synchronized (mLock) {
            if (USE_CACHE) {
                mDisplayInfoCache.remove(displayId);

                if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) {
                    mDisplayIdCache = null;
                }
            }

            final int numListeners = mDisplayListeners.size();
            for (int i = 0; i < numListeners; i++) {
                mDisplayListeners.get(i).sendDisplayEvent(displayId, event);
            }
        }
    }

调用 DisplayListenerDelegate 的 sendDisplayEvent,进而调用 mListener.onDisplayAdded(msg.arg1);,即 WindowManagerService 的 onDisplayAdded,


/*--------------DisplayManagerGlobal.java---------------------------*/
 private static final class DisplayListenerDelegate extends Handler {
        public final DisplayListener mListener;

        public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
            super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
            mListener = listener;
        }

        public void sendDisplayEvent(int displayId, int event) {
            Message msg = obtainMessage(event, displayId, 0);
            sendMessage(msg);
        }

        public void clearEvents() {
            removeCallbacksAndMessages(null);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case EVENT_DISPLAY_ADDED:
                    mListener.onDisplayAdded(msg.arg1);
                    break;
                case EVENT_DISPLAY_CHANGED:
                    mListener.onDisplayChanged(msg.arg1);
                    break;
                case EVENT_DISPLAY_REMOVED:
                    mListener.onDisplayRemoved(msg.arg1);
                    break;
            }
        }
    }
}

转到 WindowManagerService 中,

/*--------------WindowManagerService.java---------------------------*/
    @Override
    public void onDisplayAdded(int displayId) {
        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
    }
/*--------------WindowManagerService.java---------------------------*/
                    case DO_DISPLAY_ADDED:
                    synchronized (mWindowMap) {
                        handleDisplayAddedLocked(msg.arg1);
                    }
                    break;

        private void handleDisplayAddedLocked(int displayId) {
        final Display display = mDisplayManager.getDisplay(displayId);
        if (display != null) {
            createDisplayContentLocked(display);
            displayReady(displayId);
        }
    }

调用 DisplayManager 的 getDisplay,

/*--------------DisplayManager.java---------------------------*/
        public Display getDisplay(int displayId) {
        synchronized (mLock) {
            return getOrCreateDisplayLocked(displayId, false /*assumeValid*/);
        }
    }
/*--------------DisplayManager.java---------------------------*/
    //  private final SparseArray<Display> mDisplays = new SparseArray<Display>();
        private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
        Display display = mDisplays.get(displayId);
        if (display == null) {
            display = mGlobal.getCompatibleDisplay(displayId,
                    mContext.getDisplayAdjustments(displayId));
            if (display != null) {
                mDisplays.put(displayId, display);
            }
        } else if (!assumeValid && !display.isValid()) {
            display = null;
        }
        return display;
    }
/*--------------DisplayManagerGlobal.java---------------------------*/

    public Display getCompatibleDisplay(int displayId, DisplayAdjustments daj) {
        DisplayInfo displayInfo = getDisplayInfo(displayId);
        if (displayInfo == null) {
            return null;
        }
        return new Display(this, displayId, displayInfo, daj);
    }
/*--------------DisplayManagerGlobal.java---------------------------*/
//mDm DisplayManagerService
     public DisplayInfo getDisplayInfo(int displayId) {
        try {
            synchronized (mLock) {
                DisplayInfo info;
                if (USE_CACHE) {
                    info = mDisplayInfoCache.get(displayId);
                    if (info != null) {
                        return info;
                    }
                }
        //调用DisplayManagerService的getDisplayInfo,获取显示器信息
                info = mDm.getDisplayInfo(displayId);
                if (info == null) {
                    return null;
                }

                if (USE_CACHE) {
                    mDisplayInfoCache.put(displayId, info);
                }
                //前面已经注册过了,mCallback不为Null
                registerCallbackIfNeededLocked();

                if (DEBUG) {
                    Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
                }
                return info;
            }
        } catch (RemoteException ex) {
            Log.e(TAG, "Could not get display information from display manager.", ex);
            return null;
        }
    }
/*--------------DisplayManagerGlobal.java---------------------------*/
    //已经注册过了,mCallback不为Null
        private void registerCallbackIfNeededLocked() {
        if (mCallback == null) {
            mCallback = new DisplayManagerCallback();
            try {
                mDm.registerCallback(mCallback);
            } catch (RemoteException ex) {
                Log.e(TAG, "Failed to register callback with display manager service.", ex);
                mCallback = null;
            }
        }
    }
/*--------------WindowManagerService.java---------------------------*/
    //Display已经创建,创建display content
    public void createDisplayContentLocked(final Display display) {
        if (display == null) {
            throw new IllegalArgumentException("getDisplayContent: display must not be null");
        }
        getDisplayContentLocked(display.getDisplayId());
    }
/** All DisplayContents in the world, kept here */
    // SparseArray<DisplayContent> mDisplayContents = new SparseArray<DisplayContent>(2);

        public DisplayContent getDisplayContentLocked(final int displayId) {
        DisplayContent displayContent = mDisplayContents.get(displayId);
        if (displayContent == null) {
            final Display display = mDisplayManager.getDisplay(displayId);
            // 走到这个分支,创建displayContent 
            if (display != null) {
                displayContent = newDisplayContentLocked(display);
            }
        }
        return displayContent;
    }

新建一个 DisplayContent,保存到 WindowManagerService 的 mDisplayContents (displayId, displayContent)。

private DisplayContent newDisplayContentLocked(final Display display) {
        DisplayContent displayContent = new DisplayContent(display, this);
        final int displayId = display.getDisplayId();
        mDisplayContents.put(displayId, displayContent);

        DisplayInfo displayInfo = displayContent.getDisplayInfo();
        final Rect rect = new Rect();
        mDisplaySettings.getOverscanLocked(displayInfo.name, rect);
        synchronized (displayContent.mDisplaySizeLock) {
            displayInfo.overscanLeft = rect.left;
            displayInfo.overscanTop = rect.top;
            displayInfo.overscanRight = rect.right;
            displayInfo.overscanBottom = rect.bottom;
            mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
                    displayId, displayInfo);
        }
        configureDisplayPolicyLocked(displayContent);

        // TODO: Create an input channel for each display with touch capability.
        if (displayId == Display.DEFAULT_DISPLAY) {
            displayContent.mTapDetector = new StackTapPointerEventListener(this, displayContent);
            registerPointerEventListener(displayContent.mTapDetector);
        }

        return displayContent;
    }

:java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams cannot be cast to androi...

:java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams cannot be cast to androi...

:java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams cannot be cast to android.widget.RelativeLayout$LayoutParams

这个错首先说明:类型转化异常

解决方法:

一、详细检查是否将某种组件强制转换为另一种类型

二、本地声明类型是否与布局文件中的一致

三、获取的布局参数的父类和布局文件不一致

总之,要细心将布局文件类型与activity中的一致。


Android 4.4 (KitKat) 上的 Android Gallery 为 Intent.ACTION_GET_CONTENT 返回不同的 URI

在 KitKat 之前(或在新画廊之前)Intent.ACTION_GET_CONTENT返回一个这样的 URI

内容://媒体/外部/图像/媒体/3951。

使用ContentResolver和查询 MediaStore.Images.Media.DATA返回的文件 URL。

然而,在 KitKat 中,Gallery 会返回一个 URI(通过“Last”),如下所示:

内容://com.android.providers.media.documents/document/image:3951

我该如何处理?

答案1

小编典典

尝试这个:

if (Build.VERSION.SDK_INT <19){    Intent intent = new Intent();     intent.setType("image/jpeg");    intent.setAction(Intent.ACTION_GET_CONTENT);    startActivityForResult(Intent.createChooser(intent, getResources().getString(R.string.select_picture)),GALLERY_INTENT_CALLED);} else {    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);    intent.addCategory(Intent.CATEGORY_OPENABLE);    intent.setType("image/jpeg");    startActivityForResult(intent, GALLERY_KITKAT_INTENT_CALLED);}@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {    super.onActivityResult(requestCode, resultCode, data);    if (resultCode != Activity.RESULT_OK) return;    if (null == data) return;    Uri originalUri = null;    if (requestCode == GALLERY_INTENT_CALLED) {        originalUri = data.getData();    } else if (requestCode == GALLERY_KITKAT_INTENT_CALLED) {        originalUri = data.getData();        final int takeFlags = data.getFlags()                & (Intent.FLAG_GRANT_READ_URI_PERMISSION                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);        // Check for the freshest data.        getContentResolver().takePersistableUriPermission(originalUri, takeFlags);    }    loadSomeStreamAsynkTask(originalUri);}

大概需要

@SuppressLint(“NewApi”)

为了

获取PersistableUriPermission

Android Camera Orientation ISsue

Android Camera Orientation ISsue

Some devices doesn''t rotate image after it was taken but just write its orientation information into Exif data. So before using taken photo you should call method like :

private int resolveBitmapOrientation(File bitmapFile) throws IOException { ExifInterface exif = null; exif = new ExifInterface(bitmapFile.getAbsolutePath()); return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); }

private Bitmap applyOrientation(Bitmap bitmap, int orientation) {
        int rotate = 0;
        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_270:
                rotate = 270;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                rotate = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_90:
                rotate = 90;
                break;
            default:
                return bitmap;
        }

        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        Matrix mtx = new Matrix();
        mtx.postRotate(rotate);
        return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
    }

and use this new bitmap in your listview. Or it''s even better to call this methods just after your photo was taken and override it with new rotated one.

我们今天的关于android camera setDisplayOrientation(90)在不同的设备中失败the android camera encountered的分享已经告一段落,感谢您的关注,如果您想了解更多关于(OK) Android graphic (12)—display 上层相关概念、关系 - mLogicalDisplays.get (Display.DEFAULT_DISPLAY)、:java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams cannot be cast to androi...、Android 4.4 (KitKat) 上的 Android Gallery 为 Intent.ACTION_GET_CONTENT 返回不同的 URI、Android Camera Orientation ISsue的相关信息,请在本站查询。

本文标签: