1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.framebufferizer.utils;
18 
19 import com.android.framebufferizer.NativeRenderer;
20 import java.awt.geom.AffineTransform;
21 import java.awt.image.BufferedImage;
22 import java.awt.image.DataBufferInt;
23 import java.awt.image.RenderedImage;
24 import java.util.Iterator;
25 import java.util.Map;
26 import java.util.Set;
27 import java.awt.image.ColorModel;
28 import java.awt.image.DirectColorModel;
29 import java.awt.image.Raster;
30 import java.awt.image.WritableRaster;
31 import javax.swing.*;
32 import java.awt.*;
33 import java.awt.event.*;
34 
35 public class FrameBufferBuffer extends JPanel implements ComponentListener, MouseMotionListener,
36         MouseListener {
37     public class MagnifiedView extends JPanel implements ComponentListener {
38         private BufferedImage mImage;
39 
MagnifiedView()40         protected MagnifiedView() {
41             addComponentListener(this);
42         }
43 
44         @Override
componentResized(ComponentEvent e)45         public void componentResized(ComponentEvent e) {
46             synchronized (this) {
47                 mImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
48             }
49         }
50 
51         @Override
componentMoved(ComponentEvent e)52         public void componentMoved(ComponentEvent e) {
53 
54         }
55 
56         @Override
componentShown(ComponentEvent e)57         public void componentShown(ComponentEvent e) {
58 
59         }
60 
61         @Override
componentHidden(ComponentEvent e)62         public void componentHidden(ComponentEvent e) {
63 
64         }
65 
d()66         public int d() {
67             return getWidth() / 5;
68         }
69 
draw(RenderedImage image)70         public void draw(RenderedImage image) {
71             if (mImage == null)
72                 return;
73             Graphics2D gc = mImage.createGraphics();
74             gc.drawRenderedImage(image, AffineTransform.getScaleInstance(5.0, 5.0));
75             repaint();
76         }
77 
78         @Override
paint(Graphics g)79         public void paint(Graphics g) {
80             synchronized (this) {
81                 g.drawImage(mImage, 0, 0, null);
82             }
83         }
84 
85     }
86 
87     public static enum EVENT_RESULT{
88         NONE(0), CONFIRM(1) ,CANCEL(2);
89         private int id;
90 
EVENT_RESULT(int id)91         EVENT_RESULT(int id){
92           this.id = id;
93         }
94 
getValue()95         public int getValue(){
96           return id;
97         }
98     }
99 
100     public class ConfigSelector extends JPanel implements ActionListener {
101         private final String languages[];
102 
103         {
104             languages = NativeRenderer.getLanguageIdList();
105         }
106 
107         private final String layouts[] = NativeRenderer.getAvailableLayouts();
108         private JComboBox<String> deviceSelector = new JComboBox(DeviceInfoDB.Device.values());
109         private JCheckBox magnifiedCheckbox = new JCheckBox("Magnified");
110         private JCheckBox invertedCheckbox = new JCheckBox("Inverted");
111 
112         private JComboBox<String> localeSelector = new JComboBox(languages);
113         private JTextField confirmationMessage = new JTextField();
114 
115         private JComboBox<String> layoutSelector = new JComboBox(layouts);
116 
ConfigSelector()117         protected ConfigSelector() {
118             System.err.println("ConfigSelector");
119             this.setLayout(new GridBagLayout());
120 
121             GridBagConstraints c = null;
122 
123             c = new GridBagConstraints();
124             c.gridx = 0;
125             c.gridy = 0;
126             this.add(new JLabel("Select Device:"), c);
127 
128             deviceSelector.addActionListener(this);
129             c = new GridBagConstraints();
130             c.gridx = 1;
131             c.gridy = 0;
132             c.fill = GridBagConstraints.HORIZONTAL;
133             c.gridwidth = 2;
134             this.add(deviceSelector, c);
135 
136             c = new GridBagConstraints();
137             c.gridx = 0;
138             c.gridy = 1;
139             this.add(new JLabel("Select Locale:"), c);
140 
141             localeSelector.addActionListener(this);
142             c = new GridBagConstraints();
143             c.gridx = 1;
144             c.gridy = 1;
145             c.gridwidth = 2;
146             c.fill = GridBagConstraints.HORIZONTAL;
147             this.add(localeSelector, c);
148 
149             c = new GridBagConstraints();
150             c.gridx = 0;
151             c.gridy = 2;
152             this.add(new JLabel("Select Layout:"), c);
153 
154             layoutSelector.addActionListener(this);
155             c = new GridBagConstraints();
156             c.gridx = 1;
157             c.gridy = 2;
158             c.gridwidth = 2;
159             c.fill = GridBagConstraints.HORIZONTAL;
160             this.add(layoutSelector, c);
161 
162             c = new GridBagConstraints();
163             c.gridx = 0;
164             c.gridy = 3;
165             this.add(new JLabel("UIOptions:"), c);
166 
167             magnifiedCheckbox.addActionListener(this);
168             c = new GridBagConstraints();
169             c.gridx = 1;
170             c.gridy = 3;
171             this.add(magnifiedCheckbox, c);
172 
173             invertedCheckbox.addActionListener(this);
174             c = new GridBagConstraints();
175             c.gridx = 2;
176             c.gridy = 3;
177             this.add(invertedCheckbox, c);
178 
179             c = new GridBagConstraints();
180             c.gridx = 0;
181             c.gridy = 4;
182             this.add(new JLabel("Confirmation message:"), c);
183 
184             confirmationMessage.setText(
185                     "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW");
186             confirmationMessage.addActionListener(this);
187             c = new GridBagConstraints();
188             c.gridx = 1;
189             c.gridy = 4;
190             c.fill = GridBagConstraints.BOTH;
191             c.gridwidth = 2;
192             this.add(confirmationMessage, c);
193         }
194 
setConfiguration()195         public void setConfiguration() {
196             Config config = Config.getInstance();
197             config.setValue(Config.KEY_DEVICE, currentDevice());
198             config.setValue(Config.KEY_LOCALE, getConfigSelector().currentLocale());
199             config.setValue(Config.KEY_MAGNIFIED, getConfigSelector().magnified());
200             config.setValue(Config.KEY_INVERTED, getConfigSelector().inverted());
201             config.setValue(Config.KEY_MESSAGE, getConfigSelector().confirmationMessage());
202             config.setValue(Config.KEY_LAYOUT, getConfigSelector().currentLayout());
203         }
204 
actionPerformed(ActionEvent e)205         public void actionPerformed(ActionEvent e) {
206             setConfiguration();
207             FrameBufferBuffer.this.renderNativeBuffer();
208         }
209 
currentDevice()210         public DeviceInfoDB.Device currentDevice() {
211             return (DeviceInfoDB.Device) deviceSelector.getSelectedItem();
212         }
213 
currentLocale()214         public String currentLocale() {
215             return (String) localeSelector.getSelectedItem();
216         }
217 
currentLayout()218         public String currentLayout() {
219             return (String) layoutSelector.getSelectedItem();
220         }
221 
magnified()222         public boolean magnified() {
223             return magnifiedCheckbox.isSelected();
224         }
225 
inverted()226         public boolean inverted() {
227             return invertedCheckbox.isSelected();
228         }
229 
confirmationMessage()230         public String confirmationMessage() {
231             return confirmationMessage.getText();
232         }
233     }
234 
235     private BufferedImage mImage;
236     private DataBufferInt mBuffer;
237     private MagnifiedView mMagnifiedView;
238     private ConfigSelector mConfigSelector;
239     private JFrame mFrame;
240     private double mScale;
241 
getMagnifiedView()242     public MagnifiedView getMagnifiedView() {
243         if (mMagnifiedView == null) {
244             mMagnifiedView = new MagnifiedView();
245         }
246         return mMagnifiedView;
247     }
248 
getConfigSelector()249     public ConfigSelector getConfigSelector() {
250         if (mConfigSelector == null) {
251             mConfigSelector = new ConfigSelector();
252         }
253         return mConfigSelector;
254     }
255 
256     @Override
mouseReleased(MouseEvent e)257     public void mouseReleased(MouseEvent e) {
258         if (e.MOUSE_RELEASED == MouseEvent.MOUSE_RELEASED) {
259             double x = e.getPoint().x / mScale;
260             double y = e.getPoint().y / mScale;
261             int value = NativeRenderer.onEvent((int)x, (int)y, MouseEvent.MOUSE_RELEASED);
262             if(value == EVENT_RESULT.CONFIRM.getValue()){
263                 JOptionPane.showMessageDialog((Component) e.getSource(), "Confirm clicked.");
264             } else if (value == EVENT_RESULT.CANCEL.getValue()){
265                 JOptionPane.showMessageDialog((Component) e.getSource(), "Cancel clicked.");
266             }
267         }
268     }
269 
270     @Override
mouseClicked(MouseEvent e)271     public void mouseClicked(MouseEvent e){
272     }
273 
274     @Override
mousePressed(MouseEvent e)275     public void mousePressed(MouseEvent e){
276     }
277 
278     @Override
mouseEntered(MouseEvent e)279     public void mouseEntered(MouseEvent e){
280     }
281 
282     @Override
mouseExited(MouseEvent e)283     public void mouseExited(MouseEvent e){
284     }
285 
286     @Override
mouseDragged(MouseEvent e)287     public void mouseDragged(MouseEvent e) {
288 
289     }
290 
291     @Override
mouseMoved(MouseEvent e)292     public void mouseMoved(MouseEvent e) {
293         if (mMagnifiedView != null) {
294             final int rMask = 0xff;
295             final int gMask = 0xff00;
296             final int bMask = 0xff0000;
297             final int bpp = 24;
298             int d = mMagnifiedView.d();
299             int x = e.getX() - d / 2;
300             if (x + d > mImage.getWidth()) {
301                 x = mImage.getWidth() - d;
302             }
303             if (x < 0) {
304                 x = 0;
305             }
306             int y = e.getY() - d / 2;
307             if (y + d > mImage.getHeight()) {
308                 y = mImage.getHeight() - d;
309             }
310             if (y < 0) {
311                 y = 0;
312             }
313             if (mImage.getWidth() < d) {
314                 d = mImage.getWidth();
315             }
316             if (mImage.getHeight() < d) {
317                 d = mImage.getHeight();
318             }
319             mMagnifiedView.draw(mImage.getSubimage(x, y, d, d));
320         }
321     }
322 
setDefaultValues()323     public void setDefaultValues() {
324         Map<String, Object> configMap = Config.getInstance().getConfiguration();
325         if (configMap != null) {
326             Set set = configMap.entrySet();
327             Iterator iterator = set.iterator();
328             while (iterator.hasNext()) {
329                 Map.Entry<String, Object> element = (Map.Entry) iterator.next();
330                 switch (element.getKey()) {
331                 case Config.KEY_DEVICE:
332                     getConfigSelector().deviceSelector
333                             .setSelectedItem((DeviceInfoDB.Device.valueOf(((String) element.getValue()))));
334                     break;
335                 case Config.KEY_LOCALE:
336                     getConfigSelector().localeSelector.setSelectedItem((String) element.getValue());
337                     break;
338                 case Config.KEY_MAGNIFIED:
339                     getConfigSelector().magnifiedCheckbox.setSelected((Boolean) element.getValue());
340                     break;
341                 case Config.KEY_INVERTED:
342                     getConfigSelector().invertedCheckbox.setSelected((Boolean) element.getValue());
343                     break;
344                 case Config.KEY_MESSAGE:
345                     getConfigSelector().confirmationMessage.setText((String) element.getValue());
346                     break;
347                 case Config.KEY_LAYOUT:
348                     getConfigSelector().layoutSelector.setSelectedItem((String) element.getValue());
349                     break;
350                 }
351             }
352         }
353     }
354 
FrameBufferBuffer()355     public FrameBufferBuffer() {
356         setSize(412, 900);
357         setPreferredSize(new Dimension(412, 900));
358         setDefaultValues();
359         renderNativeBuffer();
360         addComponentListener(this);
361         addMouseMotionListener(this);
362         addMouseListener(this);
363     }
364 
365     @Override
componentResized(ComponentEvent e)366     public void componentResized(ComponentEvent e) {
367         renderNativeBuffer();
368         repaint();
369     }
370 
371     @Override
componentMoved(ComponentEvent e)372     public void componentMoved(ComponentEvent e) {
373 
374     }
375 
376     @Override
componentShown(ComponentEvent e)377     public void componentShown(ComponentEvent e) {
378 
379     }
380 
381     @Override
componentHidden(ComponentEvent e)382     public void componentHidden(ComponentEvent e) {
383 
384     }
385 
386     @Override
paint(Graphics g)387     public void paint(Graphics g) {
388         synchronized (this) {
389             g.drawImage(mImage, 0, 0, null);
390         }
391     }
392 
setFrame(JFrame frame)393     public void setFrame(JFrame frame) {
394         mFrame = frame;
395     }
396 
renderNativeBuffer()397     public void renderNativeBuffer() {
398         final int LAYOUT_EXAMPLE_ERROR = -2;
399         final int FRAME_BUFFER_ERROR = -1;
400         DeviceInfo deviceInfo = DeviceInfoDB.getDeviceInfo(getConfigSelector().currentDevice());
401         boolean magnified = getConfigSelector().magnified();
402         boolean inverted = getConfigSelector().inverted();
403 
404         int w = deviceInfo.getWidthPx();
405         int h = deviceInfo.getHeightPx();
406         final int linestride = w;
407         final int rMask = 0xff;
408         final int gMask = 0xff00;
409         final int bMask = 0xff0000;
410         final int bpp = 24;
411         int error = 0;
412         synchronized (this) {
413             mBuffer = new DataBufferInt(h * linestride);
414             WritableRaster raster = Raster.createPackedRaster(mBuffer, w, h, linestride,
415                     new int[] { rMask, gMask, bMask }, null);
416             ColorModel colorModel = new DirectColorModel(bpp, rMask, gMask, bMask);
417             BufferedImage image = new BufferedImage(colorModel, raster, true, null);
418             NativeRenderer.setDeviceInfo(deviceInfo, magnified, inverted, getConfigSelector().currentLayout());
419             NativeRenderer.setLanguage(getConfigSelector().currentLocale());
420             NativeRenderer.setConfimationMessage(getConfigSelector().confirmationMessage());
421             error = NativeRenderer.renderBuffer(0, 0, w, h, linestride, mBuffer.getData());
422             if(error == FRAME_BUFFER_ERROR){
423                 System.out.println("Error framebuffer not initilized " + error);
424             } else if(error == LAYOUT_EXAMPLE_ERROR){
425                 System.out.println("Error layout example not initilized " + error);
426             } else if (error != 0) {
427                 System.out.println("Error rendering native buffer " + error);
428             }
429 
430             mImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
431             Graphics2D gc = mImage.createGraphics();
432             if (w / (double) h > getWidth() / (double) getHeight()) {
433                 mScale = (double) getWidth() / (double) w;
434             } else {
435                 mScale = (double) getHeight() / (double) h;
436             }
437             gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
438             gc.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
439             gc.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
440             gc.drawRenderedImage(image, AffineTransform.getScaleInstance(mScale, mScale));
441         }
442         repaint();
443     }
444 }
445