root/java/org/gnu/emacs/EmacsWindowAttachmentManager.java

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. attachWindow
  2. getAttachedWindow
  3. detachWindow
  4. destroy
  5. registerWindowConsumer
  6. registerWindow
  7. removeWindowConsumer
  8. detachWindow
  9. noticeIconified
  10. noticeDeiconified
  11. copyWindows

     1 /* Communication module for Android terminals.  -*- c-file-style: "GNU" -*-
     2 
     3 Copyright (C) 2023 Free Software Foundation, Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify
     8 it under the terms of the GNU General Public License as published by
     9 the Free Software Foundation, either version 3 of the License, or (at
    10 your option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    19 
    20 package org.gnu.emacs;
    21 
    22 import java.util.ArrayList;
    23 import java.util.List;
    24 
    25 import android.app.ActivityOptions;
    26 import android.content.Intent;
    27 import android.os.Build;
    28 import android.util.Log;
    29 
    30 /* Code to paper over the differences in lifecycles between
    31    "activities" and windows.  There are four interfaces to an instance
    32    of this class:
    33 
    34      registerWindowConsumer (WindowConsumer)
    35      registerWindow (EmacsWindow)
    36      removeWindowConsumer (WindowConsumer)
    37      removeWindow (EmacsWindow)
    38 
    39    A WindowConsumer is expected to allow an EmacsWindow to be attached
    40    to it, and be created or destroyed.
    41 
    42    Every time a window is created, registerWindow checks the list of
    43    window consumers.  If a consumer exists and does not currently have
    44    a window of its own attached, it gets the new window.  Otherwise,
    45    the window attachment manager starts a new consumer.
    46 
    47    Every time a consumer is registered, registerWindowConsumer checks
    48    the list of available windows.  If a window exists and is not
    49    currently attached to a consumer, then the consumer gets it.
    50 
    51    Finally, every time a window is removed, the consumer is
    52    destroyed.  */
    53 
    54 public final class EmacsWindowAttachmentManager
    55 {
    56   private final static String TAG = "EmacsWindowAttachmentManager";
    57 
    58   /* The single window attachment manager ``object''.  */
    59   public static final EmacsWindowAttachmentManager MANAGER;
    60 
    61   static
    62   {
    63     MANAGER = new EmacsWindowAttachmentManager ();
    64   };
    65 
    66   public interface WindowConsumer
    67   {
    68     public void attachWindow (EmacsWindow window);
    69     public EmacsWindow getAttachedWindow ();
    70     public void detachWindow ();
    71     public void destroy ();
    72   };
    73 
    74   /* List of currently attached window consumers.  */
    75   public List<WindowConsumer> consumers;
    76 
    77   /* List of currently attached windows.  */
    78   public List<EmacsWindow> windows;
    79 
    80   public
    81   EmacsWindowAttachmentManager ()
    82   {
    83     consumers = new ArrayList<WindowConsumer> ();
    84     windows = new ArrayList<EmacsWindow> ();
    85   }
    86 
    87   public void
    88   registerWindowConsumer (WindowConsumer consumer)
    89   {
    90     Log.d (TAG, "registerWindowConsumer " + consumer);
    91 
    92     consumers.add (consumer);
    93 
    94     for (EmacsWindow window : windows)
    95       {
    96         if (window.getAttachedConsumer () == null)
    97           {
    98             Log.d (TAG, "registerWindowConsumer: attaching " + window);
    99             consumer.attachWindow (window);
   100             return;
   101           }
   102       }
   103 
   104     Log.d (TAG, "registerWindowConsumer: sendWindowAction 0, 0");
   105     EmacsNative.sendWindowAction ((short) 0, 0);
   106   }
   107 
   108   public synchronized void
   109   registerWindow (EmacsWindow window)
   110   {
   111     Intent intent;
   112     ActivityOptions options;
   113 
   114     Log.d (TAG, "registerWindow (maybe): " + window);
   115 
   116     if (windows.contains (window))
   117       /* The window is already registered.  */
   118       return;
   119 
   120     Log.d (TAG, "registerWindow: " + window);
   121 
   122     windows.add (window);
   123 
   124     for (WindowConsumer consumer : consumers)
   125       {
   126         if (consumer.getAttachedWindow () == null)
   127           {
   128             Log.d (TAG, "registerWindow: attaching " + consumer);
   129             consumer.attachWindow (window);
   130             return;
   131           }
   132       }
   133 
   134     intent = new Intent (EmacsService.SERVICE,
   135                          EmacsMultitaskActivity.class);
   136     intent.addFlags (Intent.FLAG_ACTIVITY_NEW_DOCUMENT
   137                      | Intent.FLAG_ACTIVITY_NEW_TASK
   138                      | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
   139 
   140     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
   141       EmacsService.SERVICE.startActivity (intent);
   142     else
   143       {
   144         /* Specify the desired window size.  */
   145         options = ActivityOptions.makeBasic ();
   146         options.setLaunchBounds (window.getGeometry ());
   147         EmacsService.SERVICE.startActivity (intent,
   148                                             options.toBundle ());
   149       }
   150 
   151     Log.d (TAG, "registerWindow: startActivity");
   152   }
   153 
   154   public void
   155   removeWindowConsumer (WindowConsumer consumer, boolean isFinishing)
   156   {
   157     EmacsWindow window;
   158 
   159     Log.d (TAG, "removeWindowConsumer " + consumer);
   160 
   161     window = consumer.getAttachedWindow ();
   162 
   163     if (window != null)
   164       {
   165         Log.d (TAG, "removeWindowConsumer: detaching " + window);
   166 
   167         consumer.detachWindow ();
   168         window.onActivityDetached (isFinishing);
   169       }
   170 
   171     Log.d (TAG, "removeWindowConsumer: removing " + consumer);
   172     consumers.remove (consumer);
   173   }
   174 
   175   public synchronized void
   176   detachWindow (EmacsWindow window)
   177   {
   178     WindowConsumer consumer;
   179 
   180     Log.d (TAG, "detachWindow " + window);
   181 
   182     if (window.getAttachedConsumer () != null)
   183       {
   184         consumer = window.getAttachedConsumer ();
   185 
   186         Log.d (TAG, "detachWindow: removing" + consumer);
   187 
   188         consumers.remove (consumer);
   189         consumer.destroy ();
   190       }
   191 
   192     windows.remove (window);
   193   }
   194 
   195   public void
   196   noticeIconified (WindowConsumer consumer)
   197   {
   198     EmacsWindow window;
   199 
   200     Log.d (TAG, "noticeIconified " + consumer);
   201 
   202     /* If a window is attached, send the appropriate iconification
   203        events.  */
   204     window = consumer.getAttachedWindow ();
   205 
   206     if (window != null)
   207       window.noticeIconified ();
   208   }
   209 
   210   public void
   211   noticeDeiconified (WindowConsumer consumer)
   212   {
   213     EmacsWindow window;
   214 
   215     Log.d (TAG, "noticeDeiconified " + consumer);
   216 
   217     /* If a window is attached, send the appropriate iconification
   218        events.  */
   219     window = consumer.getAttachedWindow ();
   220 
   221     if (window != null)
   222       window.noticeDeiconified ();
   223   }
   224 
   225   public synchronized List<EmacsWindow>
   226   copyWindows ()
   227   {
   228     return new ArrayList<EmacsWindow> (windows);
   229   }
   230 };

/* [<][>][^][v][top][bottom][index][help] */