Reply
Thread Tools
christexaport's Avatar
Posts: 1,589 | Thanked: 720 times | Joined on Aug 2009 @ Arlington (DFW), Texas
#11
Just getting anyone that was ever interested in developing or using a rotation solution to join my efforts for Fremantle. This is about the only way you can engage people you don't know, and everyone says "don't talk about it, do something! I've done just that, and no one else has. I'm on my own, but not powerless, believe me.
__________________
Maemo-Freak.com
"...and the Freaks shall inherit the Earth."
 
christexaport's Avatar
Posts: 1,589 | Thanked: 720 times | Joined on Aug 2009 @ Arlington (DFW), Texas
#12
I wasn't sure if this allowed portrait throught all of the UI or specific apps, but if this developer has managed to do some of the work, I'd be happy if he joined my brainstorm to help us overcome the obstacles created by rotating a UI not designed for it out of the box.

Has he created a data entry method for portrait? Does it include a T9 solution or portriat QWERTY solution? Has he figured a widget repositioning mechanism? Has the dashboard position been optimized for a portrait orientation? Has a new method for launching the Phone app been developed to replace the rotation method present out of the box?

There are many more challenges we must overcome in order to fully integrate the ASR experience into the N900 in a manner that is as painless as possible. That is the purpose of my thread, so maybe the developer of this solution will see his value in helping our cause.
__________________
Maemo-Freak.com
"...and the Freaks shall inherit the Earth."
 
thp's Avatar
Posts: 1,391 | Thanked: 4,272 times | Joined on Sep 2007 @ Vienna, Austria
#13
Since the initial announcement, I have changed the code a bit to allow the on-demand activation and deactivation of the rotation support through MCE and for a user-configurable setting:

http://repo.or.cz/w/gpodder.git?a=bl...tl/portrait.py

Because of these changes, the usage has also changed a bit:

Code:
# import the module...

main_window = ... # your main hildon.StackableWindow
app_name = 'NameOfYourApp' # the name of your app
app_version = '1.0' # the version number of your app
initial_mode = FremantleRotation.AUTOMATIC

rotation_object = FremantleRotation(app_name, main_window, app_version, initial_mode)
The rotation object then takes care of enabling and disabling the accelerometer as it is needed. You can provide a preferences UI for your app (see gPodder for an example) and then set the mode of the rotation object like this:

Code:
rotation_object.set_mode(FremantleRotation.AUTOMATIC)
rotation_object.set_mode(FremantleRotation.NEVER)
rotation_object.set_mode(FremantleRotation.ALWAYS)
You can create a hildon.PickerButton and a hildon.TouchSelector for your preferences dialog to set the mode. As an example, consult the source code of gPodder's preferences dialog:

http://repo.or.cz/w/gpodder.git?a=bl...preferences.py
 

The Following 4 Users Say Thank You to thp For This Useful Post:
Posts: 1,038 | Thanked: 737 times | Joined on Nov 2005 @ Helsinki
#14
Please make it so that in automatic mode, if user has kb open, it stays in landscape.
 

The Following 2 Users Say Thank You to konttori For This Useful Post:
thp's Avatar
Posts: 1,391 | Thanked: 4,272 times | Joined on Sep 2007 @ Vienna, Austria
#15
Originally Posted by konttori View Post
Please make it so that in automatic mode, if user has kb open, it stays in landscape.
Any documentation on how to best get a signal when the keyboard is closed/opened? (D-Bus?)
 
Khertan's Avatar
Posts: 1,012 | Thanked: 817 times | Joined on Jul 2007 @ France
#16
Your solution is nice. But you assume that the initial position of the device is landscape which be false. Here is a fix to take care of the initial orientatiom of the device :

Code:
# -*- coding: utf-8 -*-
#
# gPodder - A media aggregator and podcast client
# Copyright (c) 2005-2009 Thomas Perl and the gPodder Team
#
# gPodder is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# gPodder is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import dbus
import dbus.glib

import hildon
import osso

class FremantleRotation(object):
    """thp's screen rotation for Maemo 5

    Simply instantiate an object of this class and let it auto-rotate
    your StackableWindows depending on the device orientation.

    If you need to relayout a window, connect to its "configure-event"
    signal and measure the ratio of width/height and relayout for that.

    You can set the mode for rotation to AUTOMATIC (default), NEVER or
    ALWAYS with the set_mode() method.
    """
    AUTOMATIC, NEVER, ALWAYS = range(3)

    # Human-readable captions for the above constants
    MODE_CAPTIONS = (('Automatic'), ('Landscape'), ('Portrait'))

    # Privately-used constants
    _PORTRAIT, _LANDSCAPE = ('portrait', 'landscape')
    _ENABLE_ACCEL = 'req_accelerometer_enable'
    _DISABLE_ACCEL = 'req_accelerometer_disable'

    # Defined in mce/dbus-names.h
    _MCE_SERVICE = 'com.nokia.mce'
    _MCE_REQUEST_PATH = '/com/nokia/mce/request'
    _MCE_REQUEST_IF = 'com.nokia.mce.request'

    def __init__(self, app_name, main_window=None, version='1.0', mode=0):
        """Create a new rotation manager

        app_name    ... The name of your application (for osso.Context)
        main_window ... The root window (optional, hildon.StackableWindow)
        version     ... The version of your application (optional, string)
        mode        ... Initial mode for this manager (default: AUTOMATIC)
        """
        self._orientation = None
        self._main_window = main_window
        self._stack = hildon.WindowStack.get_default()
        self._mode = -1
        #Khertan add s for initial position
        self._last_dbus_orientation = self.get_current_orientation()
        app_id = '-'.join((app_name, str(self.__class__.__name__)))
        self._osso_context = osso.Context(app_id, version, False)
        program = hildon.Program.get_instance()
        program.connect('notify::is-topmost', self._on_topmost_changed)
        system_bus = dbus.Bus.get_system()
        system_bus.add_signal_receiver(self._on_orientation_signal, \
                signal_name='sig_device_orientation_ind', \
                dbus_interface='com.nokia.mce.signal', \
                path='/com/nokia/mce/signal')        
        self.set_mode(mode)

    #Khertan add s for initial position
    def get_current_orientation(self):
        f = open("/sys/class/i2c-adapter/i2c-3/3-001d/coord", 'r' )
        x,y,z = [int(w) for w in f.readline().split()]
        f.close()
        
        if abs(x)<500: 
          return self._LANDSCAPE
        else:
          return self._PORTRAIT
          
    def get_mode(self):
        """Get the currently-set rotation mode

        This will return one of three values: AUTOMATIC, ALWAYS or NEVER.
        """
        return self._mode

    def set_mode(self, new_mode):
        """Set the rotation mode

        You can set the rotation mode to AUTOMATIC (use hardware rotation
        info), ALWAYS (force portrait) and NEVER (force landscape).
        """
        if new_mode not in (self.AUTOMATIC, self.ALWAYS, self.NEVER):
            raise ValueError('Unknown rotation mode')

        if self._mode != new_mode:
            if self._mode == self.AUTOMATIC:
                # Remember the current "automatic" orientation for later
                self._last_dbus_orientation = self._orientation
                # Tell MCE that we don't need the accelerometer anymore
                self._send_mce_request(self._DISABLE_ACCEL)
                

            if new_mode == self.NEVER:
                self._orientation_changed(self._LANDSCAPE)
            elif new_mode == self.ALWAYS:
                self._orientation_changed(self._PORTRAIT)
            elif new_mode == self.AUTOMATIC:
                
                # Restore the last-known "automatic" orientation
                self._orientation_changed(self._last_dbus_orientation)
                # Tell MCE that we need the accelerometer again
                self._send_mce_request(self._ENABLE_ACCEL)

            self._mode = new_mode

    def _send_mce_request(self, request):
        rpc = osso.Rpc(self._osso_context)
        rpc.rpc_run(self._MCE_SERVICE, \
                    self._MCE_REQUEST_PATH, \
                    self._MCE_REQUEST_IF, \
                    request, \
                    use_system_bus=True)

    def _on_topmost_changed(self, program, property_spec):
        # XXX: This seems to never get called on Fremantle(?)
        if self._mode == self.AUTOMATIC:
            if program.get_is_topmost():
                self._send_mce_request(self._ENABLE_ACCEL)
            else:
                self._send_mce_request(self._DISABLE_ACCEL)

    def _get_main_window(self):
        if self._main_window:
            # If we have gotten the main window as parameter, return it and
            # don't try "harder" to find another window using the stack
            return self._main_window
        else:
            # The main window is at the "bottom" of the window stack, and as
            # the list we get with get_windows() is sorted "topmost first", we
            # simply take the last item of the list to get our main window
            windows = self._stack.get_windows()
            if windows:
                return windows[-1]
            else:
                return None

    def _orientation_changed(self, orientation):
        if self._orientation == orientation:
            # Ignore repeated requests
            return

        flags = hildon.PORTRAIT_MODE_SUPPORT
        if orientation == self._PORTRAIT:
            flags |= hildon.PORTRAIT_MODE_REQUEST

        window = self._get_main_window()
        if window is not None:
            hildon.hildon_gtk_window_set_portrait_flags(window, flags)

        self._orientation = orientation

    def _on_orientation_signal(self, orientation, stand, face, x, y, z):
        if orientation in (self._PORTRAIT, self._LANDSCAPE):
            if self._mode == self.AUTOMATIC:
                # Automatically set the rotation based on hardware orientation
                self._orientation_changed(orientation)
            else:
                # Ignore orientation changes for non-automatic modes, but save
                # the current orientation for "automatic" mode later on
                self._last_dbus_orientation = orientation
 

The Following 5 Users Say Thank You to Khertan For This Useful Post:
Posts: 15 | Thanked: 87 times | Joined on Dec 2009
#17
It would be really nice to have this kind of stuff incorporated in the PyMaemo wiki pages. Would you prefer cutting and pasting this stuff (or having it cut and pasted ) to the wiki or should I just provide a link to this thread in the wiki?

Cheers,

ma.
 
Khertan's Avatar
Posts: 1,012 | Thanked: 817 times | Joined on Jul 2007 @ France
#18
Copy paste it ... it ll be better than founding it on talk
 
Posts: 15 | Thanked: 87 times | Joined on Dec 2009
#19
Originally Posted by Khertan View Post
Copy paste it ... it ll be better than founding it on talk
It's there:

http://wiki.maemo.org/PyMaemo/PortraitMode

Thanks!
 

The Following 3 Users Say Thank You to mairas For This Useful Post:
Posts: 2 | Thanked: 3 times | Joined on Jan 2010 @ Minnesota, USA
#20
Here's a variant on Khertan's initial position detection by using D-Bus instead of accessing the device directly. This should make it a little less hardware dependent in case the accelerometer hardware changes in future devices.

Code:
# -*- coding: utf-8 -*-
#
# gPodder - A media aggregator and podcast client
# Copyright (c) 2005-2009 Thomas Perl and the gPodder Team
#
# gPodder is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# gPodder is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import dbus
import dbus.glib

import hildon
import osso


class FremantleRotation(object):
    """thp's screen rotation for Maemo 5

    Simply instantiate an object of this class and let it auto-rotate
    your StackableWindows depending on the device orientation.

    If you need to relayout a window, connect to its "configure-event"
    signal and measure the ratio of width/height and relayout for that.

    You can set the mode for rotation to AUTOMATIC (default), NEVER or
    ALWAYS with the set_mode() method.
    """
    AUTOMATIC, NEVER, ALWAYS = range(3)

    # Human-readable captions for the above constants
    MODE_CAPTIONS = ("Automatic", "Landscape", "Portrait")

    # Privately-used constants
    _PORTRAIT, _LANDSCAPE = ('portrait', 'landscape')
    _ENABLE_ACCEL = 'req_accelerometer_enable'
    _DISABLE_ACCEL = 'req_accelerometer_disable'

    # Defined in mce/dbus-names.h
    _MCE_SERVICE = 'com.nokia.mce'
    _MCE_REQUEST_PATH = '/com/nokia/mce/request'
    _MCE_REQUEST_IF = 'com.nokia.mce.request'

    def __init__(self, app_name, main_window=None, version='1.0', mode=0):
        """Create a new rotation manager

        app_name    ... The name of your application (for osso.Context)
        main_window ... The root window (optional, hildon.StackableWindow)
        version     ... The version of your application (optional, string)
        mode        ... Initial mode for this manager (default: AUTOMATIC)
        """
        self._orientation = None
        self._main_window = main_window
        self._stack = hildon.WindowStack.get_default()
        self._mode = -1
        app_id = '-'.join((app_name, self.__class__.__name__))
        self._osso_context = osso.Context(app_id, version, False)
        self._last_dbus_orientation = self._get_current_orientation()
        program = hildon.Program.get_instance()
        program.connect('notify::is-topmost', self._on_topmost_changed)
        system_bus = dbus.Bus.get_system()
        system_bus.add_signal_receiver(self._on_orientation_signal, \
                signal_name='sig_device_orientation_ind', \
                dbus_interface='com.nokia.mce.signal', \
                path='/com/nokia/mce/signal')
        self.set_mode(mode)

    def _get_current_orientation(self):
        """Return the current orientation
        
        Returns portrait if in portrait mode for sure, landscape if
        in landscape mode or unknown.
        """
        if self._send_mce_request('get_device_orientation', True) \
                == self._PORTRAIT:
            return self._PORTRAIT
        else:
            return self._LANDSCAPE

    def get_mode(self):
        """Get the currently-set rotation mode

        This will return one of three values: AUTOMATIC, ALWAYS or NEVER.
        """
        return self._mode

    def set_mode(self, new_mode):
        """Set the rotation mode

        You can set the rotation mode to AUTOMATIC (use hardware rotation
        info), ALWAYS (force portrait) and NEVER (force landscape).
        """
        if new_mode not in (self.AUTOMATIC, self.ALWAYS, self.NEVER):
            raise ValueError('Unknown rotation mode')

        if self._mode != new_mode:
            if self._mode == self.AUTOMATIC:
                # Remember the current "automatic" orientation for later
                self._last_dbus_orientation = self._orientation
                # Tell MCE that we don't need the accelerometer anymore
                self._send_mce_request(self._DISABLE_ACCEL)

            if new_mode == self.NEVER:
                self._orientation_changed(self._LANDSCAPE)
            elif new_mode == self.ALWAYS:
                self._orientation_changed(self._PORTRAIT)
            elif new_mode == self.AUTOMATIC:
                # Restore the last-known "automatic" orientation
                self._orientation_changed(self._last_dbus_orientation)
                # Tell MCE that we need the accelerometer again
                self._send_mce_request(self._ENABLE_ACCEL)

            self._mode = new_mode

    def _send_mce_request(self, request, wait_reply=False):
        rpc = osso.Rpc(self._osso_context)
        return rpc.rpc_run(self._MCE_SERVICE,
                    self._MCE_REQUEST_PATH,
                    self._MCE_REQUEST_IF,
                    request,
                    wait_reply=wait_reply,
                    use_system_bus=True)

    def _on_topmost_changed(self, program, property_spec):
        # XXX: This seems to never get called on Fremantle(?)
        if self._mode == self.AUTOMATIC:
            if program.get_is_topmost():
                self._send_mce_request(self._ENABLE_ACCEL)
            else:
                self._send_mce_request(self._DISABLE_ACCEL)

    def _get_main_window(self):
        if self._main_window:
            # If we have gotten the main window as parameter, return it and
            # don't try "harder" to find another window using the stack
            return self._main_window
        else:
            # The main window is at the "bottom" of the window stack, and as
            # the list we get with get_windows() is sorted "topmost first", we
            # simply take the last item of the list to get our main window
            windows = self._stack.get_windows()
            if windows:
                return windows[-1]
            else:
                return None

    def _orientation_changed(self, orientation):
        if self._orientation == orientation:
            # Ignore repeated requests
            return

        flags = hildon.PORTRAIT_MODE_SUPPORT
        if orientation == self._PORTRAIT:
            flags |= hildon.PORTRAIT_MODE_REQUEST

        window = self._get_main_window()
        if window is not None:
            hildon.hildon_gtk_window_set_portrait_flags(window, flags)

        self._orientation = orientation

    def _on_orientation_signal(self, orientation, stand, face, x, y, z):
        if orientation in (self._PORTRAIT, self._LANDSCAPE):
            if self._mode == self.AUTOMATIC:
                # Automatically set the rotation based on hardware orientation
                self._orientation_changed(orientation)
            else:
                # Ignore orientation changes for non-automatic modes, but save
                # the current orientation for "automatic" mode later on
                self._last_dbus_orientation = orientation
 

The Following 3 Users Say Thank You to xorbit For This Useful Post:
Reply

Tags
code, fremantle, howto, portrait mode, python

Thread Tools

 
Forum Jump


All times are GMT. The time now is 14:58.